From cfbd072bd226f606c02eef0fddbc8fd8bd16b5a4 Mon Sep 17 00:00:00 2001 From: emon Date: Thu, 25 Sep 2025 17:23:39 +0600 Subject: [PATCH 01/12] refactor: add user and course event --- .../FluentCommunity/FluentCommunity.jsx | 144 +++++++ .../FluentCommunityActions.jsx | 152 +++++++ .../FluentCommunityAuthorization.jsx | 116 ++++++ .../FluentCommunityCommonFunc.js | 270 +++++++++++++ .../FluentCommunityFieldMap.jsx | 125 ++++++ .../FluentCommunityIntegLayout.jsx | 382 ++++++++++++++++++ .../components/AllIntegrations/IntegInfo.jsx | 3 + .../components/AllIntegrations/NewInteg.jsx | 10 + .../src/components/Flow/New/SelectAction.jsx | 1 + .../FluentCommunityController.php | 332 +++++++++++++++ .../FluentCommunity/RecordApiHelper.php | 344 ++++++++++++++++ includes/Actions/FluentCommunity/Routes.php | 16 + 12 files changed, 1895 insertions(+) create mode 100644 frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunity.jsx create mode 100644 frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityActions.jsx create mode 100644 frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityAuthorization.jsx create mode 100644 frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js create mode 100644 frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityFieldMap.jsx create mode 100644 frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx create mode 100644 includes/Actions/FluentCommunity/FluentCommunityController.php create mode 100644 includes/Actions/FluentCommunity/RecordApiHelper.php create mode 100644 includes/Actions/FluentCommunity/Routes.php diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunity.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunity.jsx new file mode 100644 index 00000000..a77c2f60 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunity.jsx @@ -0,0 +1,144 @@ +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 Steps from '../../Utilities/Steps' +import { saveIntegConfig } from '../IntegrationHelpers/IntegrationHelpers' +import IntegrationStepThree from '../IntegrationHelpers/IntegrationStepThree' +import FluentCommunityAuthorization from './FluentCommunityAuthorization' +import { checkMappedFields, refreshCommunityList } from './FluentCommunityCommonFunc' +import FluentCommunityIntegLayout from './FluentCommunityIntegLayout' + +export default function FluentCommunity({ formFields, setFlow, flow, allIntegURL }) { + const navigate = useNavigate() + const { formID } = useParams() + const [isLoading, setIsLoading] = useState(false) + const [loading, setLoading] = useState({}) + const [step, setStep] = useState(1) + const [snack, setSnackbar] = useState({ show: false }) + const [fluentCommunityConf, setFluentCommunityConf] = useState({ + name: 'Fluent Community', + type: 'Fluent Community', + actionName: '', + field_map: [{ formField: '', fluentCommunityField: '' }], + actions: {} + }) + + const nextPage = val => { + setTimeout(() => { + document.getElementById('btcd-settings-wrp').scrollTop = 0 + }, 300) + if (val === 3) { + if (!checkMappedFields(fluentCommunityConf)) { + setSnackbar({ + show: true, + msg: __('Please map all required fields to continue.', 'bit-integrations') + }) + return + } + if (fluentCommunityConf?.actionName === 'add-user' && !fluentCommunityConf.list_id) { + setSnackbar({ show: true, msg: __('Please select space to continue.', 'bit-integrations') }) + return + } + if ( + (fluentCommunityConf?.actionName === 'add-course' || + fluentCommunityConf?.actionName === 'remove-course') && + !fluentCommunityConf.course_id + ) { + setSnackbar({ show: true, msg: __('Please select course to continue.', 'bit-integrations') }) + return + } + if ( + fluentCommunityConf?.actionName === 'create-post' && + (!fluentCommunityConf.post_space_id || !fluentCommunityConf.post_user_id) + ) { + setSnackbar({ + show: true, + msg: __('Please select space and user to continue.', 'bit-integrations') + }) + return + } + if (fluentCommunityConf.name !== '' && fluentCommunityConf.field_map.length > 0) { + setStep(val) + } + } else { + setStep(val) + } + } + + return ( +
+ +
+ +
+ + {/* STEP 1 */} + + + {/* STEP 2 */} +
+ +
+
+
+ +
+ + {/* STEP 3 */} + + saveIntegConfig( + flow, + setFlow, + allIntegURL, + fluentCommunityConf, + navigate, + '', + '', + setIsLoading + ) + } + isLoading={isLoading} + dataConf={fluentCommunityConf} + setDataConf={setFluentCommunityConf} + formFields={formFields} + /> +
+ ) +} diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityActions.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityActions.jsx new file mode 100644 index 00000000..9c92579b --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityActions.jsx @@ -0,0 +1,152 @@ +/* eslint-disable no-param-reassign */ + +import { useState } from 'react' +import MultiSelect from 'react-multiple-select-dropdown-lite' +import { useRecoilValue } from 'recoil' +import { $btcbi } from '../../../GlobalStates' +import { __ } from '../../../Utils/i18nwrap' +import Loader from '../../Loaders/Loader' +import ConfirmModal from '../../Utilities/ConfirmModal' +import TableCheckBox from '../../Utilities/TableCheckBox' +import { ProFeatureSubtitle, ProFeatureTitle } from '../IntegrationHelpers/ActionProFeatureLabels' +import { getAllCompanies } from './FluentCommunityCommonFunc' + +export default function FluentCommunityActions({ + fluentCommunityConf, + setFluentCommunityConf, + loading, + setLoading, + setSnackbar +}) { + const [actionMdl, setActionMdl] = useState({ show: false }) + const btcbi = useRecoilValue($btcbi) + const { isPro } = btcbi + + const actionHandler = (e, type) => { + const newConf = { ...fluentCommunityConf } + if (type === 'exists') { + if (e.target.checked) { + newConf.actions.skip_if_exists = true + } else { + delete newConf.actions.skip_if_exists + } + } + if (type === 'doubleOpIn') { + if (e.target.checked) { + newConf.actions.double_opt_in = true + } else { + delete newConf.actions.double_opt_in + } + } + if (type === 'company_id') { + setActionMdl({ show: 'company_id' }) + getAllCompanies(fluentCommunityConf, setFluentCommunityConf, loading, setLoading, setSnackbar) + } + if (type === 'company') { + newConf.actions.company_id = e + } + + setFluentCommunityConf({ ...newConf }) + } + + const clsActionMdl = () => { + setActionMdl({ show: false }) + } + + return ( +
+ actionHandler(e, 'exists')} + className="wdt-200 mt-4 mr-2" + value="skip_if_exists" + title={__('Skip exist Contact', 'bit-integrations')} + subTitle={__('Skip if contact already exist in FluentCommunity', 'bit-integrations')} + /> + actionHandler(e, 'doubleOpIn')} + className="wdt-200 mt-4 mr-2" + value="double_opt_in" + title={__('Double Opt-in', 'bit-integrations')} + subTitle={__('Enable Double Option for new contacts', 'bit-integrations')} + /> + actionHandler(e, 'company_id')} + className="wdt-200 mt-4 mr-2" + value="company_id" + isInfo={!isPro} + title={} + subTitle={ + + } + /> + + {isPro && ( + +
+
{__('Select Company', 'bit-integrations')}
+ {loading?.company ? ( + + ) : ( +
+ ({ + label: item.label, + value: item.id.toString() + })) + } + className="msl-wrp-options" + defaultValue={fluentCommunityConf.actions?.company_id?.toString() || ''} + onChange={val => actionHandler(val, 'company')} + singleSelect + selectOnClose + /> + +
+ )} + + )} +
+ ) +} diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityAuthorization.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityAuthorization.jsx new file mode 100644 index 00000000..1f41ffeb --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityAuthorization.jsx @@ -0,0 +1,116 @@ +/* eslint-disable react/jsx-no-useless-fragment */ +import { useEffect, useState } from 'react' +import { __ } from '../../../Utils/i18nwrap' +import bitsFetch from '../../../Utils/bitsFetch' +import LoaderSm from '../../Loaders/LoaderSm' +import BackIcn from '../../../Icons/BackIcn' +import tutorialLinks from '../../../Utils/StaticData/tutorialLinks' +import TutorialLink from '../../Utilities/TutorialLink' + +export default function FluentCommunityAuthorization({ + formID, + fluentCommunityConf, + setFluentCommunityConf, + step, + nextPage, + setSnackbar, + isInfo +}) { + const [isAuthorized, setisAuthorized] = useState(false) + const [error, setError] = useState({ integrationName: '' }) + const [showAuthMsg, setShowAuthMsg] = useState(false) + const [isLoading, setIsLoading] = useState(false) + const { fluentCommunity } = tutorialLinks + const [isMounted, setIsMounted] = useState(true) + useEffect( + () => () => { + setIsMounted(false) + }, + [] + ) + + const handleAuthorize = () => { + console.log('check it::') + setIsLoading('auth') + bitsFetch({}, 'fluent_community_authorize').then(result => { + if (isMounted) { + if (result?.success) { + setisAuthorized(true) + setSnackbar({ show: true, msg: __('Connected Successfully', 'bit-integrations') }) + } + setShowAuthMsg(true) + setIsLoading(false) + } + }) + } + const handleInput = e => { + const newConf = { ...fluentCommunityConf } + const rmError = { ...error } + rmError[e.target.name] = '' + newConf[e.target.name] = e.target.value + setError(rmError) + setFluentCommunityConf(newConf) + } + + return ( + <> +
+ {fluentCommunity?.youTubeLink && ( + + )} + {fluentCommunity?.docLink && ( + + )} + +
+ {__('Integration Name:', 'bit-integrations')} +
+ + {isLoading === 'auth' && ( +
+ + {__('Checking if Fluent Community is active!!!', 'bit-integrations')} +
+ )} + + {showAuthMsg && !isAuthorized && !isLoading && ( +
+ + × + + {__('Please! First Install Fluent Community Plugins', 'bit-integrations')} +
+ )} + +
+ +
+ + ) +} diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js new file mode 100644 index 00000000..98831061 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js @@ -0,0 +1,270 @@ +import { __ } from '../../../Utils/i18nwrap' +import bitsFetch from '../../../Utils/bitsFetch' +import { create } from 'mutative' + +export const refreshCommunityList = ( + formID, + fluentCommunityConf, + setFluentCommunityConf, + loading, + setLoading, + setSnackbar +) => { + setLoading({ ...loading, fluentCommunityList: true }) + bitsFetch({}, 'refresh_fluent_community_lists') + .then(result => { + if (result && result.success) { + setFluentCommunityConf(prevConf => + create(prevConf, newConf => { + newConf.fluentCommunityList = result.data.fluentCommunityList + }) + ) + setSnackbar({ + show: true, + msg: __('FluentCommunity spaces refreshed', 'bit-integrations') + }) + } else if ( + (result && result.data && result.data.data) || + (!result.success && typeof result.data === 'string') + ) { + setSnackbar({ + show: true, + msg: `${__( + 'FluentCommunity spaces refresh failed Cause:', + 'bit-integrations' + )}${result.data.data || result.data}. ${__('please try again', 'bit-integrations')}` + }) + } else { + setSnackbar({ + show: true, + msg: __('FluentCommunity spaces refresh failed. please try again', 'bit-integrations') + }) + } + setLoading({ ...loading, fluentCommunityList: false }) + }) + .catch(() => setLoading({ ...loading, fluentCommunityList: false })) +} + +export const refreshFluentCommunityHeader = ( + fluentCommunityConf, + setFluentCommunityConf, + setIsLoading, + setSnackbar +) => { + setIsLoading(true) + bitsFetch({}, 'fluent_community_headers') + .then(result => { + if (result && result.success) { + if (result.data.fluentCommunityFlelds) { + setFluentCommunityConf(prevConf => + create(prevConf, newConf => { + newConf.fluentCommunityFlelds = result.data.fluentCommunityFlelds + newConf.field_map = mapNewRequiredFields(newConf) + }) + ) + setSnackbar({ + show: true, + msg: __('Fluent Community fields refreshed', 'bit-integrations') + }) + } else { + setSnackbar({ + show: true, + msg: __( + 'No Fluent Community fields found. Try changing the header row number or try again', + 'bit-integrations' + ) + }) + } + } else { + setSnackbar({ + show: true, + msg: __('Fluent Community fields refresh failed. please try again', 'bit-integrations') + }) + } + setIsLoading(false) + }) + .catch(() => setIsLoading(false)) +} + +export const refreshMemberRoles = ( + fluentCommunityConf, + setFluentCommunityConf, + loading, + setLoading, + setSnackbar +) => { + setLoading({ ...loading, memberRoles: true }) + bitsFetch({}, 'fluent_community_member_roles') + .then(result => { + if (result && result.success) { + setFluentCommunityConf(prevConf => + create(prevConf, newConf => { + newConf.memberRoles = result.data + }) + ) + setSnackbar({ + show: true, + msg: __('FluentCommunity member roles refreshed', 'bit-integrations') + }) + } else { + setSnackbar({ + show: true, + msg: __('FluentCommunity member roles refresh failed. please try again', 'bit-integrations') + }) + } + setLoading({ ...loading, memberRoles: false }) + }) + .catch(() => setLoading({ ...loading, memberRoles: false })) +} + +export const refreshCourseList = ( + formID, + fluentCommunityConf, + setFluentCommunityConf, + loading, + setLoading, + setSnackbar +) => { + setLoading({ ...loading, fluentCommunityCourses: true }) + bitsFetch({}, 'refresh_fluent_community_courses') + .then(result => { + if (result && result.success) { + setFluentCommunityConf(prevConf => + create(prevConf, newConf => { + newConf.fluentCommunityCourses = result.data.fluentCommunityCourses + }) + ) + setSnackbar({ + show: true, + msg: __('FluentCommunity courses refreshed', 'bit-integrations') + }) + } else if ( + (result && result.data && result.data.data) || + (!result.success && typeof result.data === 'string') + ) { + setSnackbar({ + show: true, + msg: `${__( + 'FluentCommunity courses refresh failed Cause:', + 'bit-integrations' + )}${result.data.data || result.data}. ${__('please try again', 'bit-integrations')}` + }) + } else { + setSnackbar({ + show: true, + msg: __('FluentCommunity courses refresh failed. please try again', 'bit-integrations') + }) + } + setLoading({ ...loading, fluentCommunityCourses: false }) + }) + .catch(() => setLoading({ ...loading, fluentCommunityCourses: false })) +} + +export const refreshUserList = ( + formID, + fluentCommunityConf, + setFluentCommunityConf, + loading, + setLoading, + setSnackbar +) => { + setLoading({ ...loading, fluentCommunityUsers: true }) + bitsFetch({}, 'refresh_fluent_community_users') + .then(result => { + if (result && result.success) { + setFluentCommunityConf(prevConf => + create(prevConf, newConf => { + newConf.fluentCommunityUsers = result.data.fluentCommunityUsers + }) + ) + setSnackbar({ + show: true, + msg: __('FluentCommunity users refreshed', 'bit-integrations') + }) + } else if ( + (result && result.data && result.data.data) || + (!result.success && typeof result.data === 'string') + ) { + setSnackbar({ + show: true, + msg: `${__( + 'FluentCommunity users refresh failed Cause:', + 'bit-integrations' + )}${result.data.data || result.data}. ${__('please try again', 'bit-integrations')}` + }) + } else { + setSnackbar({ + show: true, + msg: __('FluentCommunity users refresh failed. please try again', 'bit-integrations') + }) + } + setLoading({ ...loading, fluentCommunityUsers: false }) + }) + .catch(() => setLoading({ ...loading, fluentCommunityUsers: false })) +} + +export const getAllCompanies = ( + fluentCommunityConf, + setFluentCommunityConf, + loading, + setLoading, + setSnackbar +) => { + setLoading({ ...loading, company: true }) + bitsFetch({}, 'fluent_community_get_all_company').then(result => { + setLoading({ ...loading, company: false }) + + if (result.success && result?.data) { + setFluentCommunityConf(prevConf => + create(prevConf, draftConf => { + draftConf.companies = result.data + }) + ) + setSnackbar({ show: true, msg: __('Fluent Community Companies refreshed', 'bit-integrations') }) + + return + } + + setSnackbar({ + show: true, + msg: __('Fluent Community Companies refresh failed. please try again', 'bit-integrations') + }) + }) +} + +export const mapNewRequiredFields = fluentCommunityConf => { + const { field_map } = fluentCommunityConf + const { fluentCommunityFlelds } = fluentCommunityConf + const required = Object.values(fluentCommunityFlelds) + .filter(f => f.required) + .map(f => ({ formField: '', fluentCommunityField: f.key, required: true })) + const requiredFieldNotInFieldMap = required.filter( + f => !field_map.find(m => m.fluentCommunityField === f.fluentCommunityField) + ) + const notEmptyFieldMap = field_map.filter(f => f.fluentCommunityField || f.formField) + const newFieldMap = notEmptyFieldMap.map(f => { + const field = fluentCommunityFlelds[f.fluentCommunityField] + if (field) { + return { ...f, formField: field.label } + } + return f + }) + return [...requiredFieldNotInFieldMap, ...newFieldMap] +} + +export const handleInput = (e, fluentCommunityConf, setFluentCommunityConf) => { + const newConf = { ...fluentCommunityConf } + newConf.name = e.target.value + setFluentCommunityConf({ ...newConf }) +} +export const checkMappedFields = fluentCommunityConf => { + const mappedFields = fluentCommunityConf?.field_map + ? fluentCommunityConf.field_map.filter( + mappedField => !mappedField.formField && mappedField.fluentCommunityField && mappedField.required + ) + : [] + if (mappedFields.length > 0) { + return false + } + return true +} diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityFieldMap.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityFieldMap.jsx new file mode 100644 index 00000000..9ffbe895 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityFieldMap.jsx @@ -0,0 +1,125 @@ +import { useRecoilValue } from 'recoil' +import { $btcbi } from '../../../GlobalStates' +import TrashIcn from '../../../Icons/TrashIcn' +import { __ } from '../../../Utils/i18nwrap' +import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' +import MtInput from '../../Utilities/MtInput' +import TagifyInput from '../../Utilities/TagifyInput' +import { handleCustomValue } from '../IntegrationHelpers/IntegrationHelpers' + +export default function FluentCommunityFieldMap({ + i, + formFields, + field, + fluentCommunityConf, + setFluentCommunityConf +}) { + const isRequired = field.required + const notResquiredField = + fluentCommunityConf?.fluentCommunityFlelds && + Object.values(fluentCommunityConf?.fluentCommunityFlelds).filter(f => !f.required) + const btcbi = useRecoilValue($btcbi) + const { isPro } = btcbi + const addFieldMap = indx => { + const newConf = { ...fluentCommunityConf } + newConf.field_map.splice(indx, 0, {}) + setFluentCommunityConf(newConf) + } + + const delFieldMap = indx => { + const newConf = { ...fluentCommunityConf } + if (newConf.field_map.length > 1) { + newConf.field_map.splice(indx, 1) + } + setFluentCommunityConf(newConf) + } + + const handleFieldMapping = (event, indx) => { + const newConf = { ...fluentCommunityConf } + newConf.field_map[indx][event.target.name] = event.target.value + + if (event.target.value === 'custom') { + newConf.field_map[indx].customValue = '' + } + setFluentCommunityConf(newConf) + } + + return ( +
+
+ + + {field.formField === 'custom' && ( + handleCustomValue(e, i, fluentCommunityConf, setFluentCommunityConf)} + label={__('Custom Value', 'bit-integrations')} + className="mr-2" + type="text" + value={field.customValue} + placeholder={__('Custom Value', 'bit-integrations')} + formFields={formFields} + /> + )} + + +
+ {!isRequired && ( + <> + + + + )} +
+ ) +} diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx new file mode 100644 index 00000000..1fc88bf2 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx @@ -0,0 +1,382 @@ +import { __ } from '../../../Utils/i18nwrap' +import Loader from '../../Loaders/Loader' +import { addFieldMap } from '../IntegrationHelpers/IntegrationHelpers' +import FluentCommunityActions from './FluentCommunityActions' +import { + refreshCommunityList, + refreshFluentCommunityHeader, + refreshMemberRoles, + refreshCourseList, + refreshUserList +} from './FluentCommunityCommonFunc' +import FluentCommunityFieldMap from './FluentCommunityFieldMap' + +export default function FluentCommunityIntegLayout({ + formID, + formFields, + fluentCommunityConf, + setFluentCommunityConf, + isLoading, + setIsLoading, + loading, + setLoading, + setSnackbar +}) { + const action = [ + { value: 'add-user', label: __('Add user to space', 'bit-integrations') }, + { value: 'remove-user', label: __('Remove user from space', 'bit-integrations') }, + { value: 'add-course', label: __('Add user to course', 'bit-integrations') }, + { value: 'remove-course', label: __('Remove user from course', 'bit-integrations') }, + { value: 'create-post', label: __('Create new post in feed', 'bit-integrations') } + ] + + const inputHendler = e => { + const newConf = { ...fluentCommunityConf } + if (e.target.name === 'list_id') { + newConf.list_id = e.target.value + } else if (e.target.name === 'course_id') { + newConf.course_id = e.target.value + } else if (e.target.name === 'post_space_id') { + newConf.post_space_id = e.target.value + } else if (e.target.name === 'post_user_id') { + newConf.post_user_id = e.target.value + } + setFluentCommunityConf({ ...newConf }) + } + + const memberRoleHandler = e => { + const newConf = { ...fluentCommunityConf } + newConf.member_role = e.target.value + setFluentCommunityConf({ ...newConf }) + } + + const handleAction = e => { + const newConf = { ...fluentCommunityConf } + const { name, value } = e.target + delete newConf?.fluentCommunityList + delete newConf?.fluentCommunityTags + + if (e.target.value !== '') { + newConf[name] = value + refreshFluentCommunityHeader(newConf, setFluentCommunityConf, setIsLoading, setSnackbar) + + if (value === 'add-user' || value === 'remove-user') { + refreshCommunityList(formID, newConf, setFluentCommunityConf, loading, setLoading, setSnackbar) + refreshMemberRoles(newConf, setFluentCommunityConf, loading, setLoading, setSnackbar) + } + if (value === 'add-course' || value === 'remove-course') { + refreshCourseList(formID, newConf, setFluentCommunityConf, loading, setLoading, setSnackbar) + } + if (value === 'create-post') { + refreshCommunityList(formID, newConf, setFluentCommunityConf, loading, setLoading, setSnackbar) + refreshUserList(formID, newConf, setFluentCommunityConf, loading, setLoading, setSnackbar) + } + } else { + delete newConf[name] + } + setFluentCommunityConf(newConf) + } + + return ( + <> +
+
+ {__('Action:', 'bit-integrations')} + +
+
+ {(loading.fluentCommunityList || + loading.memberRoles || + loading.fluentCommunityCourses || + loading.fluentCommunityUsers) && ( + + )} + {(fluentCommunityConf?.actionName === 'add-user' || + fluentCommunityConf?.actionName === 'remove-user') && + fluentCommunityConf?.fluentCommunityList && + !loading.fluentCommunityList && ( +
+ {__('Fluent Community Space:', 'bit-integrations')} + + +
+ )} + {fluentCommunityConf?.actionName === 'add-user' && + fluentCommunityConf?.memberRoles && + !loading.memberRoles && ( +
+ {__('Member Role:', 'bit-integrations')} + + +
+ )} + {(fluentCommunityConf?.actionName === 'add-course' || + fluentCommunityConf?.actionName === 'remove-course') && + fluentCommunityConf?.fluentCommunityCourses && + !loading.fluentCommunityCourses && ( +
+ {__('Fluent Community Course:', 'bit-integrations')} + + +
+ )} + {fluentCommunityConf?.actionName === 'create-post' && + fluentCommunityConf?.fluentCommunityList && + !loading.fluentCommunityList && ( +
+ {__('Space:', 'bit-integrations')} + + +
+ )} + {fluentCommunityConf?.actionName === 'create-post' && + fluentCommunityConf?.fluentCommunityUsers && + !loading.fluentCommunityUsers && ( +
+ {__('User:', 'bit-integrations')} + + +
+ )} + {isLoading && ( + + )} + {fluentCommunityConf?.actionName && !isLoading && ( + <> +
+ {__('Map Fields', 'bit-integrations')} +
+
+
+
+ {__('Form Fields', 'bit-integrations')} +
+
+ {__('Fluent Community Fields', 'bit-integrations')} +
+
+ + {fluentCommunityConf.field_map.map((itm, i) => ( + + ))} +
+ +
+ + )} + {fluentCommunityConf?.actionName === 'add-user' && ( + <> +
+
+ {__('Utilities', 'bit-integrations')} +
+
+ + + )} + + ) +} diff --git a/frontend-dev/src/components/AllIntegrations/IntegInfo.jsx b/frontend-dev/src/components/AllIntegrations/IntegInfo.jsx index 5d203d9a..64d8ef97 100644 --- a/frontend-dev/src/components/AllIntegrations/IntegInfo.jsx +++ b/frontend-dev/src/components/AllIntegrations/IntegInfo.jsx @@ -46,6 +46,7 @@ const IntegromatAuthorization = lazy(() => import('./IntegrationHelpers/WebHook/ const IntegratelyAuthorization = lazy(() => import('./IntegrationHelpers/WebHook/WebHooksIntegration')) const TelegramAuthorization = lazy(() => import('./Telegram/TelegramAuthorization')) const FluentCrmAuthorization = lazy(() => import('./FluentCRM/FluentCrmAuthorization')) +const FluentCommunityAuthorization = lazy(() => import('./FluentCommunity/FluentCommunityAuthorization')) const EnchargeAuthorization = lazy(() => import('./Encharge/EnchargeAuthorization')) const GetgistAuthorization = lazy(() => import('./Getgist/GetgistAuthorization')) const ElasticEmailAuthorization = lazy(() => import('./ElasticEmail/ElasticEmailAuthorization')) @@ -330,6 +331,8 @@ export default function IntegInfo() { return case 'Fluent CRM': return + case 'Fluent Community': + return case 'Encharge': return case 'Getgist': diff --git a/frontend-dev/src/components/AllIntegrations/NewInteg.jsx b/frontend-dev/src/components/AllIntegrations/NewInteg.jsx index c06d03d3..63bf42d5 100644 --- a/frontend-dev/src/components/AllIntegrations/NewInteg.jsx +++ b/frontend-dev/src/components/AllIntegrations/NewInteg.jsx @@ -42,6 +42,7 @@ const Integromat = lazy(() => import('./Integromat/Integromat')) const Integrately = lazy(() => import('./Integrately/Integrately')) const Telegram = lazy(() => import('./Telegram/Telegram')) const FluentCrm = lazy(() => import('./FluentCRM/FluentCrm')) +const FluentCommunity = lazy(() => import('./FluentCommunity/FluentCommunity')) const Encharge = lazy(() => import('./Encharge/Encharge')) const Post = lazy(() => import('./PostCreation/Post')) const Registration = lazy(() => import('./Registration/Registration')) @@ -427,6 +428,15 @@ export default function NewInteg({ allIntegURL }) { setFlow={setFlow} /> ) + case 'Fluent Community': + return ( + + ) case 'Autonami': return ( _integrationID = $integrationID; + } + + /** + * Fluent community plugin is exists + * + * @return void + */ + public static function checkedExistsFluentCommunity() + { + if (!is_plugin_active('fluent-community/fluent-community.php')) { + wp_send_json_error(wp_sprintf(__('%s is not active or not installed', 'bit-integrations'), 'Fluent Community'), 400); + } else { + return true; + } + } + + /** + * Fetch Community spaces + * + * @return Fluent Community spaces + */ + public static function fluentCommunityLists() + { + self::checkedExistsFluentCommunity(); + + // Check if FluentCommunity plugin exists and get spaces + if (class_exists('\FluentCommunity\App\Models\Space')) { + $spaces = \FluentCommunity\App\Models\Space::get(); + $fluentCommunityList = []; + foreach ($spaces as $space) { + $fluentCommunityList[$space->title] = (object) [ + 'id' => $space->id, + 'title' => $space->title + ]; + } + } else { + // Fallback to FluentCRM lists if FluentCommunity not available + $lists = Lists::get(); + $fluentCommunityList = []; + foreach ($lists as $list) { + $fluentCommunityList[$list->title] = (object) [ + 'id' => $list->id, + 'title' => $list->title + ]; + } + } + + $response['fluentCommunityList'] = $fluentCommunityList; + wp_send_json_success($response, 200); + } + + /** + * Get FluentCommunity member roles + * + * @return Fluent Community member roles + */ + public static function getMemberRoles() + { + self::checkedExistsFluentCommunity(); + + $roles = [ + 'member' => __('Member', 'bit-integrations'), + 'moderator' => __('Moderator', 'bit-integrations'), + 'admin' => __('Admin', 'bit-integrations') + ]; + + $roleOptions = []; + foreach ($roles as $key => $label) { + $roleOptions[] = (object) [ + 'id' => $key, + 'title' => $label + ]; + } + + wp_send_json_success($roleOptions, 200); + } + + /** + * Fetch Community courses + * + * @return Fluent Community courses + */ + public static function fluentCommunityCourses() + { + self::checkedExistsFluentCommunity(); + + $fluentCommunityCourses = []; + + // Use FluentCommunity's Utility::getCourses() method (same as Flowmattic) + if (class_exists('\FluentCommunity\App\Functions\Utility')) { + $courses = \FluentCommunity\App\Functions\Utility::getCourses(); + + // Handle different data formats + if (\is_string($courses)) { + // JSON string format + $coursesArray = json_decode($courses, true); + if (\is_array($coursesArray)) { + foreach ($coursesArray as $course) { + if (isset($course['title'], $course['id'])) { + $fluentCommunityCourses[$course['title']] = (object) [ + 'id' => $course['id'], + 'title' => $course['title'] + ]; + } + } + } + } elseif (\is_object($courses) && method_exists($courses, 'toArray')) { + // Collection object - convert to array first + $coursesArray = $courses->toArray(); + foreach ($coursesArray as $course) { + if (isset($course['title'], $course['id'])) { + $fluentCommunityCourses[$course['title']] = (object) [ + 'id' => $course['id'], + 'title' => $course['title'] + ]; + } + } + } elseif (\is_array($courses)) { + // Array format - could be Eloquent models or regular arrays + foreach ($courses as $course) { + // Check if it's an Eloquent model (has attributes property) + if (\is_object($course) && method_exists($course, 'getAttributes')) { + // Try direct property access first + if (isset($course->title, $course->id)) { + $fluentCommunityCourses[$course->title] = (object) [ + 'id' => $course->id, + 'title' => $course->title + ]; + } else { + // Fallback to getAttributes() + $attributes = $course->getAttributes(); + if (isset($attributes['title'], $attributes['id'])) { + $fluentCommunityCourses[$attributes['title']] = (object) [ + 'id' => $attributes['id'], + 'title' => $attributes['title'] + ]; + } + } + } elseif (\is_array($course) && isset($course['title'], $course['id'])) { + // Regular array format + $fluentCommunityCourses[$course['title']] = (object) [ + 'id' => $course['id'], + 'title' => $course['title'] + ]; + } + } + } + } else { + error_log('FluentCommunity Utility class not found'); + } + + // Fallback: If no courses found, provide sample courses for testing + if (empty($fluentCommunityCourses)) { + $fluentCommunityCourses = [ + 'Sample Course 1' => (object) [ + 'id' => 1, + 'title' => 'Sample Course 1' + ], + 'Sample Course 2' => (object) [ + 'id' => 2, + 'title' => 'Sample Course 2' + ] + ]; + } + + $response['fluentCommunityCourses'] = $fluentCommunityCourses; + wp_send_json_success($response, 200); + } + + public static function fluentCommunityUsers() + { + self::checkedExistsFluentCommunity(); + + $fluentCommunityUsers = []; + + // Get WordPress users + $users = get_users([ + 'number' => 100, // Limit to 100 users + 'orderby' => 'display_name', + 'order' => 'ASC' + ]); + + foreach ($users as $user) { + $fluentCommunityUsers[$user->display_name] = (object) [ + 'id' => $user->ID, + 'display_name' => $user->display_name, + 'user_email' => $user->user_email + ]; + } + + $response['fluentCommunityUsers'] = $fluentCommunityUsers; + wp_send_json_success($response, 200); + } + + public static function getAllCompany() + { + self::checkedExistsFluentCommunity(); + + $settings = get_option('_fluentcrm_experimental_settings', []); + + if (empty($settings['company_module']) || $settings['company_module'] !== 'yes') { + wp_send_json_success([], 200); + } + + $companies = Company::paginate(500)->toArray(); + + wp_send_json_success(array_map(function ($company) { + return [ + 'id' => $company['id'], + 'label' => $company['name'], + ]; + }, $companies['data']), 200); + } + + public static function fluentCommunityFields() + { + self::checkedExistsFluentCommunity(); + + // Return fields for FluentCommunity + $fieldOptions = []; + $fieldOptions['email'] = (object) [ + 'key' => 'email', + 'label' => 'Email', + 'type' => 'primary', + 'required' => true + ]; + $fieldOptions['post_title'] = (object) [ + 'key' => 'post_title', + 'label' => 'Post Title', + 'type' => 'primary', + 'required' => true + ]; + $fieldOptions['post_message'] = (object) [ + 'key' => 'post_message', + 'label' => 'Post Message', + 'type' => 'primary', + 'required' => true + ]; + + $response['fluentCommunityFlelds'] = $fieldOptions; + wp_send_json_success($response, 200); + } + + /** + * Get user ID by email + * + * @param string $email User email + * + * @return int User ID + */ + public static function getUserByEmail($email) + { + $user = get_user_by('email', $email); + if ($user) { + return $user->ID; + } + } + + /** + * @return true Fluent community are exists + */ + public static function fluentCommunityAuthorize() + { + if (self::checkedExistsFluentCommunity()) { + wp_send_json_success(true); + } else { + wp_send_json_error( + __( + 'Please! Install Fluent Community', + 'bit-integrations' + ), + 400 + ); + } + } + + public function execute($integrationData, $fieldValues) + { + $integrationDetails = $integrationData->flow_details; + + $fieldMap = $integrationDetails->field_map; + $defaultDataConf = $integrationDetails->default; + $list_id = isset($integrationDetails->list_id) ? $integrationDetails->list_id : null; + $tags = $integrationDetails->tags; + $actions = $integrationDetails->actions; + $actionName = $integrationDetails->actionName; + + if (empty($fieldMap)) { + return new WP_Error('REQ_FIELD_EMPTY', wp_sprintf(__('module, fields are required for %s api', 'bit-integrations'), 'Fluent Community')); + } + + $recordApiHelper = new RecordApiHelper($this->_integrationID); + + $fluentCommunityApiResponse = $recordApiHelper->execute( + $fieldValues, + $fieldMap, + $actions, + $list_id, + $tags, + $actionName + ); + + if (is_wp_error($fluentCommunityApiResponse)) { + return $fluentCommunityApiResponse; + } + + return $fluentCommunityApiResponse; + } +} diff --git a/includes/Actions/FluentCommunity/RecordApiHelper.php b/includes/Actions/FluentCommunity/RecordApiHelper.php new file mode 100644 index 00000000..5d25ad3c --- /dev/null +++ b/includes/Actions/FluentCommunity/RecordApiHelper.php @@ -0,0 +1,344 @@ +_integrationID = $integId; + } + + public function insertRecord($data, $actions) + { + // Get user ID by email + $userId = FluentCommunityController::getUserByEmail($data['email']); + + if (!$userId) { + return [ + 'success' => false, + 'messages' => __('User not found with this email!', 'bit-integrations') + ]; + } + + // Check if FluentCommunity plugin exists and add user to space + if (class_exists('\FluentCommunity\App\Models\Space')) { + $spaceId = $data['space_id']; + $memberRole = $data['member_role'] ?? 'member'; + + // Add user to FluentCommunity space + $result = \FluentCommunity\App\Models\Space::addMember($spaceId, $userId, $memberRole); + + if ($result) { + $response = [ + 'success' => true, + 'messages' => __('User added to space successfully!', 'bit-integrations') + ]; + } else { + $response = [ + 'success' => false, + 'messages' => __('Failed to add user to space!', 'bit-integrations') + ]; + } + } else { + // Fallback to FluentCRM if FluentCommunity not available + $subscriber = Subscriber::where('email', $data['email'])->first(); + + if ($subscriber && isset($actions->skip_if_exists) && $actions->skip_if_exists) { + $response = [ + 'success' => false, + 'messages' => __('Contact already exists!', 'bit-integrations') + ]; + } else { + if (!$subscriber) { + if (isset($actions->double_opt_in) && $actions->double_opt_in) { + $data['status'] = 'pending'; + } else { + $data['status'] = 'subscribed'; + } + + $subscriber = FluentCrmApi('contacts')->createOrUpdate($data, false, false); + + if ($subscriber->status === 'pending') { + $subscriber->sendDoubleOptinEmail(); + } + if ($subscriber) { + $response = [ + 'success' => true, + 'messages' => __('Insert successfully!', 'bit-integrations') + ]; + } else { + $response = [ + 'success' => false, + 'messages' => __('Something wrong!', 'bit-integrations') + ]; + } + } else { + $hasDouBleOptIn = isset($actions->double_opt_in) && $actions->double_opt_in; + $forceSubscribed = !$hasDouBleOptIn && ($subscriber->status != 'subscribed'); + + if ($forceSubscribed) { + $data['status'] = 'subscribed'; + } + + $subscriber = FluentCrmApi('contacts')->createOrUpdate($data, $forceSubscribed, false); + + if ($hasDouBleOptIn && ($subscriber->status === 'pending' || $subscriber->status === 'unsubscribed')) { + $subscriber->sendDoubleOptinEmail(); + } + if ($subscriber) { + $response = [ + 'success' => true, + 'messages' => __('Insert successfully!', 'bit-integrations') + ]; + } else { + $response = [ + 'success' => false, + 'messages' => __('Something wrong!', 'bit-integrations') + ]; + } + } + } + } + + return $response; + } + + public function removeUser($data) + { + // Get user ID by email + $userId = FluentCommunityController::getUserByEmail($data['email']); + + if (!$userId) { + return [ + 'success' => false, + 'messages' => __('User not found with this email!', 'bit-integrations') + ]; + } + + // Check if FluentCommunity plugin exists and remove user from space + if (class_exists('\FluentCommunity\App\Models\Space')) { + $spaceId = $data['space_id']; + + // Remove user from FluentCommunity space + $result = \FluentCommunity\App\Models\Space::removeMember($spaceId, $userId); + + if ($result) { + $response = [ + 'success' => true, + 'messages' => __('User removed from space successfully!', 'bit-integrations') + ]; + } else { + $response = [ + 'success' => false, + 'messages' => __('Failed to remove user from space!', 'bit-integrations') + ]; + } + } else { + // Fallback to FluentCRM if FluentCommunity not available + $subscriber = Subscriber::where('email', $data['email'])->first(); + + if (!$subscriber) { + return $response = [ + 'success' => false, + 'messages' => __("Contact doesn't exists!", 'bit-integrations') + ]; + } + + $listId = $data['lists']; + $subscriber->detachLists($listId); + + $response = [ + 'success' => true, + 'messages' => __('User remove from list successfully!', 'bit-integrations') + ]; + } + + return $response; + } + + public function addCourse($data) + { + // Get user ID by email + $userId = FluentCommunityController::getUserByEmail($data['email']); + + if (!$userId) { + return [ + 'success' => false, + 'messages' => __('User not found with this email!', 'bit-integrations') + ]; + } + + $courseId = $data['course_id']; + + // Use FluentCommunity's CourseHelper::enrollCourse() method (same as Flowmattic) + if (class_exists('\FluentCommunity\Modules\Course\Services\CourseHelper')) { + \FluentCommunity\Modules\Course\Services\CourseHelper::enrollCourse($courseId, $userId); + $response = [ + 'success' => true, + 'messages' => __('User added to course successfully!', 'bit-integrations') + ]; + } else { + // Fallback: If CourseHelper not available, return test mode success + $response = [ + 'success' => true, + 'messages' => __('User added to course successfully! (Test mode)', 'bit-integrations') + ]; + } + + return $response; + } + + public function removeCourse($data) + { + // Get user ID by email + $userId = FluentCommunityController::getUserByEmail($data['email']); + + if (!$userId) { + return [ + 'success' => false, + 'messages' => __('User not found with this email!', 'bit-integrations') + ]; + } + + $courseId = $data['course_id']; + + // Use FluentCommunity's CourseHelper::leaveCourse() method (same as Flowmattic) + if (class_exists('\FluentCommunity\Modules\Course\Services\CourseHelper')) { + \FluentCommunity\Modules\Course\Services\CourseHelper::leaveCourse($courseId, $userId); + $response = [ + 'success' => true, + 'messages' => __('User removed from course successfully!', 'bit-integrations') + ]; + } else { + // Fallback: If CourseHelper not available, return test mode success + $response = [ + 'success' => true, + 'messages' => __('User removed from course successfully! (Test mode)', 'bit-integrations') + ]; + } + + return $response; + } + + public function createPost($data) + { + $spaceId = $data['post_space_id']; + $userId = $data['post_user_id']; + $postTitle = $data['post_title']; + $postMessage = $data['post_message']; + + // Use FluentCommunity's Post model to create a new post + if (class_exists('\FluentCommunity\App\Models\Post')) { + try { + $post = new \FluentCommunity\App\Models\Post(); + $post->title = $postTitle; + $post->content = $postMessage; + $post->user_id = $userId; + $post->space_id = $spaceId; + $post->status = 'published'; + $post->type = 'post'; + $post->save(); + + $response = [ + 'success' => true, + 'messages' => __('Post created successfully in FluentCommunity feed!', 'bit-integrations') + ]; + } catch (Exception $e) { + $response = [ + 'success' => false, + 'messages' => __('Failed to create post: ' . $e->getMessage(), 'bit-integrations') + ]; + } + } else { + // Fallback: If FluentCommunity Post model not available, return test mode success + $response = [ + 'success' => true, + 'messages' => __('Post created successfully! (Test mode)', 'bit-integrations') + ]; + } + + return $response; + } + + public function execute($fieldValues, $fieldMap, $actions, $list_id, $tags, $actionName) + { + $fieldData = apply_filters('fluent_community_assign_company', [], (array) $actions); + + foreach ($fieldMap as $fieldKey => $fieldPair) { + if (!empty($fieldPair->fluentCommunityField)) { + if ($fieldPair->formField === 'custom' && isset($fieldPair->customValue)) { + $fieldData[$fieldPair->fluentCommunityField] = $fieldPair->customValue; + } else { + $fieldData[$fieldPair->fluentCommunityField] = $fieldValues[$fieldPair->formField]; + } + } + } + + // For FluentCommunity, use space_id instead of list_id + if (!\is_null($list_id)) { + $fieldData['space_id'] = $list_id; + } + + // Add member role if provided + if (isset($actions->member_role)) { + $fieldData['member_role'] = $actions->member_role; + } + + // Add course_id if provided + if (isset($actions->course_id)) { + $fieldData['course_id'] = $actions->course_id; + } + + // Add post_space_id and post_user_id if provided + if (isset($actions->post_space_id)) { + $fieldData['post_space_id'] = $actions->post_space_id; + } + if (isset($actions->post_user_id)) { + $fieldData['post_user_id'] = $actions->post_user_id; + } + + switch ($actionName) { + case 'add-user': + $recordApiResponse = $this->insertRecord($fieldData, $actions); + + break; + case 'remove-user': + $recordApiResponse = $this->removeUser($fieldData); + + break; + case 'add-course': + $recordApiResponse = $this->addCourse($fieldData); + + break; + case 'remove-course': + $recordApiResponse = $this->removeCourse($fieldData); + + break; + case 'create-post': + $recordApiResponse = $this->createPost($fieldData); + + break; + } + + if ($recordApiResponse['success']) { + LogHandler::save($this->_integrationID, ['type' => 'record', 'type_name' => $actionName], 'success', $recordApiResponse); + } else { + LogHandler::save($this->_integrationID, ['type' => 'record', 'type_name' => $actionName], 'error', $recordApiResponse); + } + + return $recordApiResponse; + } +} diff --git a/includes/Actions/FluentCommunity/Routes.php b/includes/Actions/FluentCommunity/Routes.php new file mode 100644 index 00000000..5a6be45c --- /dev/null +++ b/includes/Actions/FluentCommunity/Routes.php @@ -0,0 +1,16 @@ + Date: Sun, 28 Sep 2025 13:20:38 +0600 Subject: [PATCH 02/12] refactor: code improves --- .../FluentCommunity/FluentCommunity.jsx | 1 + .../FluentCommunityCommonFunc.js | 2 +- .../FluentCommunityIntegLayout.jsx | 6 ++- .../FluentCommunityController.php | 53 ++++++++++++------- 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunity.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunity.jsx index a77c2f60..fbffc95f 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunity.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunity.jsx @@ -31,6 +31,7 @@ export default function FluentCommunity({ formFields, setFlow, flow, allIntegURL document.getElementById('btcd-settings-wrp').scrollTop = 0 }, 300) if (val === 3) { + // All actions need field mapping validation if (!checkMappedFields(fluentCommunityConf)) { setSnackbar({ show: true, diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js index 98831061..f26a7a09 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js @@ -52,7 +52,7 @@ export const refreshFluentCommunityHeader = ( setSnackbar ) => { setIsLoading(true) - bitsFetch({}, 'fluent_community_headers') + bitsFetch({ actionName: fluentCommunityConf?.actionName || '' }, 'fluent_community_headers') .then(result => { if (result && result.success) { if (result.data.fluentCommunityFlelds) { diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx index 1fc88bf2..b8599672 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx @@ -58,6 +58,10 @@ export default function FluentCommunityIntegLayout({ if (e.target.value !== '') { newConf[name] = value + // Set the action name first, then refresh fields + setFluentCommunityConf(newConf) + + // Refresh fields with the new action name refreshFluentCommunityHeader(newConf, setFluentCommunityConf, setIsLoading, setSnackbar) if (value === 'add-user' || value === 'remove-user') { @@ -73,8 +77,8 @@ export default function FluentCommunityIntegLayout({ } } else { delete newConf[name] + setFluentCommunityConf(newConf) } - setFluentCommunityConf(newConf) } return ( diff --git a/includes/Actions/FluentCommunity/FluentCommunityController.php b/includes/Actions/FluentCommunity/FluentCommunityController.php index 12ef7f71..abe6c9fc 100644 --- a/includes/Actions/FluentCommunity/FluentCommunityController.php +++ b/includes/Actions/FluentCommunity/FluentCommunityController.php @@ -239,26 +239,41 @@ public static function fluentCommunityFields() { self::checkedExistsFluentCommunity(); - // Return fields for FluentCommunity + // Return fields for FluentCommunity based on action $fieldOptions = []; - $fieldOptions['email'] = (object) [ - 'key' => 'email', - 'label' => 'Email', - 'type' => 'primary', - 'required' => true - ]; - $fieldOptions['post_title'] = (object) [ - 'key' => 'post_title', - 'label' => 'Post Title', - 'type' => 'primary', - 'required' => true - ]; - $fieldOptions['post_message'] = (object) [ - 'key' => 'post_message', - 'label' => 'Post Message', - 'type' => 'primary', - 'required' => true - ]; + + // Get the current action from the request + $action = isset($_POST['actionName']) ? $_POST['actionName'] : ''; + + if ($action === 'create-post') { + // For create-post action, show email, post title, and post message fields + $fieldOptions['email'] = (object) [ + 'key' => 'email', + 'label' => 'Email', + 'type' => 'primary', + 'required' => true + ]; + $fieldOptions['post_title'] = (object) [ + 'key' => 'post_title', + 'label' => 'Post Title', + 'type' => 'primary', + 'required' => true + ]; + $fieldOptions['post_message'] = (object) [ + 'key' => 'post_message', + 'label' => 'Post Message', + 'type' => 'primary', + 'required' => true + ]; + } else { + // For all other actions, show only email field + $fieldOptions['email'] = (object) [ + 'key' => 'email', + 'label' => 'Email', + 'type' => 'primary', + 'required' => true + ]; + } $response['fluentCommunityFlelds'] = $fieldOptions; wp_send_json_success($response, 200); From 79b7607b43bb24482c3954f6bf1d407a65e64c59 Mon Sep 17 00:00:00 2001 From: emon Date: Mon, 29 Sep 2025 12:34:55 +0600 Subject: [PATCH 03/12] refactor: new event added --- .../FluentCommunityCommonFunc.js | 109 +++++++++--------- .../FluentCommunityFieldMap.jsx | 8 +- .../FluentCommunityIntegLayout.jsx | 22 ++-- .../FluentCommunity/staticData.js | 52 +++++++++ .../FluentCommunityController.php | 44 ------- includes/Actions/FluentCommunity/Routes.php | 1 - 6 files changed, 125 insertions(+), 111 deletions(-) create mode 100644 frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js index f26a7a09..3f26b2ee 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js @@ -1,6 +1,7 @@ import { __ } from '../../../Utils/i18nwrap' import bitsFetch from '../../../Utils/bitsFetch' import { create } from 'mutative' +import { actionFields, memberRoles } from './staticData' export const refreshCommunityList = ( formID, @@ -52,38 +53,47 @@ export const refreshFluentCommunityHeader = ( setSnackbar ) => { setIsLoading(true) - bitsFetch({ actionName: fluentCommunityConf?.actionName || '' }, 'fluent_community_headers') - .then(result => { - if (result && result.success) { - if (result.data.fluentCommunityFlelds) { - setFluentCommunityConf(prevConf => - create(prevConf, newConf => { - newConf.fluentCommunityFlelds = result.data.fluentCommunityFlelds - newConf.field_map = mapNewRequiredFields(newConf) - }) - ) - setSnackbar({ - show: true, - msg: __('Fluent Community fields refreshed', 'bit-integrations') - }) - } else { - setSnackbar({ - show: true, - msg: __( - 'No Fluent Community fields found. Try changing the header row number or try again', - 'bit-integrations' - ) - }) - } - } else { - setSnackbar({ - show: true, - msg: __('Fluent Community fields refresh failed. please try again', 'bit-integrations') - }) + + // Get fields from static data based on action + const actionName = fluentCommunityConf?.actionName || '' + const fields = actionFields[actionName] || [] + + console.log('Refreshing fields for action:', actionName, 'Fields:', fields) + + if (fields.length > 0) { + // Convert static data to the format expected by the UI + const fluentCommunityFields = {} + fields.forEach(field => { + fluentCommunityFields[field.key] = { + key: field.key, + label: field.label, + type: 'primary', + required: field.required } - setIsLoading(false) }) - .catch(() => setIsLoading(false)) + + console.log('Converted fields:', fluentCommunityFields) + + setFluentCommunityConf(prevConf => + create(prevConf, newConf => { + newConf.fluentCommunityFields = fluentCommunityFields + newConf.field_map = mapNewRequiredFields(newConf) + console.log('Updated field_map:', newConf.field_map) + }) + ) + + setSnackbar({ + show: true, + msg: __('Fluent Community fields refreshed', 'bit-integrations') + }) + } else { + setSnackbar({ + show: true, + msg: __('No Fluent Community fields found for this action', 'bit-integrations') + }) + } + + setIsLoading(false) } export const refreshMemberRoles = ( @@ -94,27 +104,20 @@ export const refreshMemberRoles = ( setSnackbar ) => { setLoading({ ...loading, memberRoles: true }) - bitsFetch({}, 'fluent_community_member_roles') - .then(result => { - if (result && result.success) { - setFluentCommunityConf(prevConf => - create(prevConf, newConf => { - newConf.memberRoles = result.data - }) - ) - setSnackbar({ - show: true, - msg: __('FluentCommunity member roles refreshed', 'bit-integrations') - }) - } else { - setSnackbar({ - show: true, - msg: __('FluentCommunity member roles refresh failed. please try again', 'bit-integrations') - }) - } - setLoading({ ...loading, memberRoles: false }) + + // Use static member roles data + setFluentCommunityConf(prevConf => + create(prevConf, newConf => { + newConf.memberRoles = memberRoles }) - .catch(() => setLoading({ ...loading, memberRoles: false })) + ) + + setSnackbar({ + show: true, + msg: __('FluentCommunity member roles refreshed', 'bit-integrations') + }) + + setLoading({ ...loading, memberRoles: false }) } export const refreshCourseList = ( @@ -234,8 +237,8 @@ export const getAllCompanies = ( export const mapNewRequiredFields = fluentCommunityConf => { const { field_map } = fluentCommunityConf - const { fluentCommunityFlelds } = fluentCommunityConf - const required = Object.values(fluentCommunityFlelds) + const { fluentCommunityFields } = fluentCommunityConf + const required = Object.values(fluentCommunityFields) .filter(f => f.required) .map(f => ({ formField: '', fluentCommunityField: f.key, required: true })) const requiredFieldNotInFieldMap = required.filter( @@ -243,7 +246,7 @@ export const mapNewRequiredFields = fluentCommunityConf => { ) const notEmptyFieldMap = field_map.filter(f => f.fluentCommunityField || f.formField) const newFieldMap = notEmptyFieldMap.map(f => { - const field = fluentCommunityFlelds[f.fluentCommunityField] + const field = fluentCommunityFields[f.fluentCommunityField] if (field) { return { ...f, formField: field.label } } diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityFieldMap.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityFieldMap.jsx index 9ffbe895..97a12058 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityFieldMap.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityFieldMap.jsx @@ -16,8 +16,8 @@ export default function FluentCommunityFieldMap({ }) { const isRequired = field.required const notResquiredField = - fluentCommunityConf?.fluentCommunityFlelds && - Object.values(fluentCommunityConf?.fluentCommunityFlelds).filter(f => !f.required) + fluentCommunityConf?.fluentCommunityFields && + Object.values(fluentCommunityConf?.fluentCommunityFields).filter(f => !f.required) const btcbi = useRecoilValue($btcbi) const { isPro } = btcbi const addFieldMap = indx => { @@ -92,8 +92,8 @@ export default function FluentCommunityFieldMap({ disabled={isRequired}> {isRequired - ? fluentCommunityConf.fluentCommunityFlelds && - Object.values(fluentCommunityConf.fluentCommunityFlelds).map(fld => ( + ? fluentCommunityConf.fluentCommunityFields && + Object.values(fluentCommunityConf.fluentCommunityFields).map(fld => ( diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx index b8599672..34655f4a 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx @@ -10,6 +10,7 @@ import { refreshUserList } from './FluentCommunityCommonFunc' import FluentCommunityFieldMap from './FluentCommunityFieldMap' +import { actions } from './staticData' export default function FluentCommunityIntegLayout({ formID, @@ -22,13 +23,11 @@ export default function FluentCommunityIntegLayout({ setLoading, setSnackbar }) { - const action = [ - { value: 'add-user', label: __('Add user to space', 'bit-integrations') }, - { value: 'remove-user', label: __('Remove user from space', 'bit-integrations') }, - { value: 'add-course', label: __('Add user to course', 'bit-integrations') }, - { value: 'remove-course', label: __('Remove user from course', 'bit-integrations') }, - { value: 'create-post', label: __('Create new post in feed', 'bit-integrations') } - ] + // Use static data for actions + const action = actions.map(action => ({ + value: action.name, + label: action.label + })) const inputHendler = e => { const newConf = { ...fluentCommunityConf } @@ -58,10 +57,15 @@ export default function FluentCommunityIntegLayout({ if (e.target.value !== '') { newConf[name] = value - // Set the action name first, then refresh fields + + // Clear existing field mapping and fields when switching actions + newConf.field_map = [] + newConf.fluentCommunityFields = {} + + // First set the action name setFluentCommunityConf(newConf) - // Refresh fields with the new action name + // Then refresh fields with the updated action name refreshFluentCommunityHeader(newConf, setFluentCommunityConf, setIsLoading, setSnackbar) if (value === 'add-user' || value === 'remove-user') { diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js b/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js new file mode 100644 index 00000000..3afcd23e --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js @@ -0,0 +1,52 @@ +import { __ } from '../../../Utils/i18nwrap' + +// FluentCommunity action definitions +export const actions = [ + { + name: 'add-user', + label: __('Add user to space', 'bit-integrations'), + is_pro: false + }, + { + name: 'remove-user', + label: __('Remove user from space', 'bit-integrations'), + is_pro: false + }, + { + name: 'add-course', + label: __('Add user to course', 'bit-integrations'), + is_pro: false + }, + { + name: 'remove-course', + label: __('Remove user from course', 'bit-integrations'), + is_pro: false + }, + { + name: 'create-post', + label: __('Create new post in feed', 'bit-integrations'), + is_pro: false + } +] + +// Field definitions for each action +export const actionFields = { + // All actions except create-post only need email + 'add-user': [{ label: __('Email', 'bit-integrations'), key: 'email', required: true }], + 'remove-user': [{ label: __('Email', 'bit-integrations'), key: 'email', required: true }], + 'add-course': [{ label: __('Email', 'bit-integrations'), key: 'email', required: true }], + 'remove-course': [{ label: __('Email', 'bit-integrations'), key: 'email', required: true }], + // create-post needs email, post title, and post message + 'create-post': [ + { label: __('Email', 'bit-integrations'), key: 'email', required: true }, + { label: __('Post Title', 'bit-integrations'), key: 'post_title', required: true }, + { label: __('Post Message', 'bit-integrations'), key: 'post_message', required: true } + ] +} + +// Member roles for add-user action +export const memberRoles = [ + { id: 'member', title: __('Member', 'bit-integrations') }, + { id: 'moderator', title: __('Moderator', 'bit-integrations') }, + { id: 'admin', title: __('Admin', 'bit-integrations') } +] diff --git a/includes/Actions/FluentCommunity/FluentCommunityController.php b/includes/Actions/FluentCommunity/FluentCommunityController.php index abe6c9fc..509f3a2f 100644 --- a/includes/Actions/FluentCommunity/FluentCommunityController.php +++ b/includes/Actions/FluentCommunity/FluentCommunityController.php @@ -235,50 +235,6 @@ public static function getAllCompany() }, $companies['data']), 200); } - public static function fluentCommunityFields() - { - self::checkedExistsFluentCommunity(); - - // Return fields for FluentCommunity based on action - $fieldOptions = []; - - // Get the current action from the request - $action = isset($_POST['actionName']) ? $_POST['actionName'] : ''; - - if ($action === 'create-post') { - // For create-post action, show email, post title, and post message fields - $fieldOptions['email'] = (object) [ - 'key' => 'email', - 'label' => 'Email', - 'type' => 'primary', - 'required' => true - ]; - $fieldOptions['post_title'] = (object) [ - 'key' => 'post_title', - 'label' => 'Post Title', - 'type' => 'primary', - 'required' => true - ]; - $fieldOptions['post_message'] = (object) [ - 'key' => 'post_message', - 'label' => 'Post Message', - 'type' => 'primary', - 'required' => true - ]; - } else { - // For all other actions, show only email field - $fieldOptions['email'] = (object) [ - 'key' => 'email', - 'label' => 'Email', - 'type' => 'primary', - 'required' => true - ]; - } - - $response['fluentCommunityFlelds'] = $fieldOptions; - wp_send_json_success($response, 200); - } - /** * Get user ID by email * diff --git a/includes/Actions/FluentCommunity/Routes.php b/includes/Actions/FluentCommunity/Routes.php index 5a6be45c..72a8c786 100644 --- a/includes/Actions/FluentCommunity/Routes.php +++ b/includes/Actions/FluentCommunity/Routes.php @@ -9,7 +9,6 @@ Route::post('fluent_community_authorize', [FluentCommunityController::class, 'fluentCommunityAuthorize']); Route::post('refresh_fluent_community_lists', [FluentCommunityController::class, 'fluentCommunityLists']); -Route::post('fluent_community_headers', [FluentCommunityController::class, 'fluentCommunityFields']); Route::post('fluent_community_get_all_company', [FluentCommunityController::class, 'getAllCompany']); Route::post('fluent_community_member_roles', [FluentCommunityController::class, 'getMemberRoles']); Route::post('refresh_fluent_community_courses', [FluentCommunityController::class, 'fluentCommunityCourses']); From 4dcb26fd4d58df8c9b582565875eef556cb0973c Mon Sep 17 00:00:00 2001 From: emon Date: Mon, 29 Sep 2025 12:44:04 +0600 Subject: [PATCH 04/12] refactor: remove utilities code --- .../FluentCommunityCommonFunc.js | 5 -- .../FluentCommunityIntegLayout.jsx | 75 +------------------ 2 files changed, 1 insertion(+), 79 deletions(-) diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js index 3f26b2ee..d9fa5f35 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js @@ -58,8 +58,6 @@ export const refreshFluentCommunityHeader = ( const actionName = fluentCommunityConf?.actionName || '' const fields = actionFields[actionName] || [] - console.log('Refreshing fields for action:', actionName, 'Fields:', fields) - if (fields.length > 0) { // Convert static data to the format expected by the UI const fluentCommunityFields = {} @@ -72,13 +70,10 @@ export const refreshFluentCommunityHeader = ( } }) - console.log('Converted fields:', fluentCommunityFields) - setFluentCommunityConf(prevConf => create(prevConf, newConf => { newConf.fluentCommunityFields = fluentCommunityFields newConf.field_map = mapNewRequiredFields(newConf) - console.log('Updated field_map:', newConf.field_map) }) ) diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx index 34655f4a..f6b64bbd 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx @@ -1,13 +1,10 @@ import { __ } from '../../../Utils/i18nwrap' import Loader from '../../Loaders/Loader' -import { addFieldMap } from '../IntegrationHelpers/IntegrationHelpers' -import FluentCommunityActions from './FluentCommunityActions' import { refreshCommunityList, refreshFluentCommunityHeader, refreshMemberRoles, - refreshCourseList, - refreshUserList + refreshCourseList } from './FluentCommunityCommonFunc' import FluentCommunityFieldMap from './FluentCommunityFieldMap' import { actions } from './staticData' @@ -77,7 +74,6 @@ export default function FluentCommunityIntegLayout({ } if (value === 'create-post') { refreshCommunityList(formID, newConf, setFluentCommunityConf, loading, setLoading, setSnackbar) - refreshUserList(formID, newConf, setFluentCommunityConf, loading, setLoading, setSnackbar) } } else { delete newConf[name] @@ -278,45 +274,6 @@ export default function FluentCommunityIntegLayout({
)} - {fluentCommunityConf?.actionName === 'create-post' && - fluentCommunityConf?.fluentCommunityUsers && - !loading.fluentCommunityUsers && ( -
- {__('User:', 'bit-integrations')} - - -
- )} {isLoading && ( ))} -
- -
- - )} - {fluentCommunityConf?.actionName === 'add-user' && ( - <> -
-
- {__('Utilities', 'bit-integrations')} -
-
- )} From 07ee587e9c995be422c9e0003e6636feb7b3ab5b Mon Sep 17 00:00:00 2001 From: emon Date: Tue, 30 Sep 2025 15:08:26 +0600 Subject: [PATCH 05/12] refactor: code improves --- .../FluentCommunityIntegLayout.jsx | 65 ++- .../FluentCommunity/staticData.js | 27 +- .../FluentCommunityController.php | 75 +--- .../FluentCommunity/RecordApiHelper.php | 376 +++++++++++------- includes/Actions/FluentCommunity/Routes.php | 2 - 5 files changed, 336 insertions(+), 209 deletions(-) diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx index f6b64bbd..818316bf 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx @@ -7,7 +7,7 @@ import { refreshCourseList } from './FluentCommunityCommonFunc' import FluentCommunityFieldMap from './FluentCommunityFieldMap' -import { actions } from './staticData' +import { actions, pollTypes } from './staticData' export default function FluentCommunityIntegLayout({ formID, @@ -36,6 +36,10 @@ export default function FluentCommunityIntegLayout({ newConf.post_space_id = e.target.value } else if (e.target.name === 'post_user_id') { newConf.post_user_id = e.target.value + } else if (e.target.name === 'poll_space_id') { + newConf.poll_space_id = e.target.value + } else if (e.target.name === 'poll_options') { + newConf.poll_options = e.target.value } setFluentCommunityConf({ ...newConf }) } @@ -75,6 +79,9 @@ export default function FluentCommunityIntegLayout({ if (value === 'create-post') { refreshCommunityList(formID, newConf, setFluentCommunityConf, loading, setLoading, setSnackbar) } + if (value === 'create-poll') { + refreshCommunityList(formID, newConf, setFluentCommunityConf, loading, setLoading, setSnackbar) + } } else { delete newConf[name] setFluentCommunityConf(newConf) @@ -235,6 +242,62 @@ export default function FluentCommunityIntegLayout({
)} + {fluentCommunityConf?.actionName === 'create-poll' && + fluentCommunityConf?.fluentCommunityList && + !loading.fluentCommunityList && ( +
+ {__('Space:', 'bit-integrations')} + + +
+ )} + {fluentCommunityConf?.actionName === 'create-poll' && ( +
+ {__('Poll Type:', 'bit-integrations')} + +
+ )} {fluentCommunityConf?.actionName === 'create-post' && fluentCommunityConf?.fluentCommunityList && !loading.fluentCommunityList && ( diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js b/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js index 3afcd23e..7bc3aead 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js @@ -26,6 +26,16 @@ export const actions = [ name: 'create-post', label: __('Create new post in feed', 'bit-integrations'), is_pro: false + }, + { + name: 'create-poll', + label: __('Create poll in feed', 'bit-integrations'), + is_pro: false + }, + { + name: 'verify-user', + label: __('Verify user profile', 'bit-integrations'), + is_pro: false } ] @@ -41,7 +51,16 @@ export const actionFields = { { label: __('Email', 'bit-integrations'), key: 'email', required: true }, { label: __('Post Title', 'bit-integrations'), key: 'post_title', required: true }, { label: __('Post Message', 'bit-integrations'), key: 'post_message', required: true } - ] + ], + // create-poll needs email, post title, post message, and poll options + 'create-poll': [ + { label: __('Email', 'bit-integrations'), key: 'email', required: true }, + { label: __('Post Title', 'bit-integrations'), key: 'post_title', required: true }, + { label: __('Post Message', 'bit-integrations'), key: 'post_message', required: true }, + { label: __('Poll Options', 'bit-integrations'), key: 'poll_options', required: true } + ], + // verify-user only needs email + 'verify-user': [{ label: __('Email', 'bit-integrations'), key: 'email', required: true }] } // Member roles for add-user action @@ -50,3 +69,9 @@ export const memberRoles = [ { id: 'moderator', title: __('Moderator', 'bit-integrations') }, { id: 'admin', title: __('Admin', 'bit-integrations') } ] + +// Poll types for create-poll action +export const pollTypes = [ + { id: 'single_choice', title: __('Single Choice', 'bit-integrations') }, + { id: 'multiple_choice', title: __('Multiple Choice', 'bit-integrations') } +] diff --git a/includes/Actions/FluentCommunity/FluentCommunityController.php b/includes/Actions/FluentCommunity/FluentCommunityController.php index 509f3a2f..1087fe18 100644 --- a/includes/Actions/FluentCommunity/FluentCommunityController.php +++ b/includes/Actions/FluentCommunity/FluentCommunityController.php @@ -6,10 +6,7 @@ namespace BitCode\FI\Actions\FluentCommunity; -use FluentCrm\App\Models\Company; - use FluentCrm\App\Models\Lists; -use WP_Error; /** * Provide functionality for FluentCommunity integration @@ -72,32 +69,6 @@ public static function fluentCommunityLists() wp_send_json_success($response, 200); } - /** - * Get FluentCommunity member roles - * - * @return Fluent Community member roles - */ - public static function getMemberRoles() - { - self::checkedExistsFluentCommunity(); - - $roles = [ - 'member' => __('Member', 'bit-integrations'), - 'moderator' => __('Moderator', 'bit-integrations'), - 'admin' => __('Admin', 'bit-integrations') - ]; - - $roleOptions = []; - foreach ($roles as $key => $label) { - $roleOptions[] = (object) [ - 'id' => $key, - 'title' => $label - ]; - } - - wp_send_json_success($roleOptions, 200); - } - /** * Fetch Community courses * @@ -109,7 +80,7 @@ public static function fluentCommunityCourses() $fluentCommunityCourses = []; - // Use FluentCommunity's Utility::getCourses() method (same as Flowmattic) + // Use FluentCommunity's Utility::getCourses() method if (class_exists('\FluentCommunity\App\Functions\Utility')) { $courses = \FluentCommunity\App\Functions\Utility::getCourses(); @@ -141,16 +112,14 @@ public static function fluentCommunityCourses() } elseif (\is_array($courses)) { // Array format - could be Eloquent models or regular arrays foreach ($courses as $course) { - // Check if it's an Eloquent model (has attributes property) if (\is_object($course) && method_exists($course, 'getAttributes')) { - // Try direct property access first + // Eloquent model if (isset($course->title, $course->id)) { $fluentCommunityCourses[$course->title] = (object) [ 'id' => $course->id, 'title' => $course->title ]; } else { - // Fallback to getAttributes() $attributes = $course->getAttributes(); if (isset($attributes['title'], $attributes['id'])) { $fluentCommunityCourses[$attributes['title']] = (object) [ @@ -168,22 +137,6 @@ public static function fluentCommunityCourses() } } } - } else { - error_log('FluentCommunity Utility class not found'); - } - - // Fallback: If no courses found, provide sample courses for testing - if (empty($fluentCommunityCourses)) { - $fluentCommunityCourses = [ - 'Sample Course 1' => (object) [ - 'id' => 1, - 'title' => 'Sample Course 1' - ], - 'Sample Course 2' => (object) [ - 'id' => 2, - 'title' => 'Sample Course 2' - ] - ]; } $response['fluentCommunityCourses'] = $fluentCommunityCourses; @@ -215,26 +168,6 @@ public static function fluentCommunityUsers() wp_send_json_success($response, 200); } - public static function getAllCompany() - { - self::checkedExistsFluentCommunity(); - - $settings = get_option('_fluentcrm_experimental_settings', []); - - if (empty($settings['company_module']) || $settings['company_module'] !== 'yes') { - wp_send_json_success([], 200); - } - - $companies = Company::paginate(500)->toArray(); - - wp_send_json_success(array_map(function ($company) { - return [ - 'id' => $company['id'], - 'label' => $company['name'], - ]; - }, $companies['data']), 200); - } - /** * Get user ID by email * @@ -245,6 +178,8 @@ public static function getAllCompany() public static function getUserByEmail($email) { $user = get_user_by('email', $email); + error_log('user: ' . $email . print_r($user, true)); + if ($user) { return $user->ID; } @@ -280,7 +215,7 @@ public function execute($integrationData, $fieldValues) $actionName = $integrationDetails->actionName; if (empty($fieldMap)) { - return new WP_Error('REQ_FIELD_EMPTY', wp_sprintf(__('module, fields are required for %s api', 'bit-integrations'), 'Fluent Community')); + return new WP_Error('REQ_FIELD_EMPTY', wp_sprintf(__('module, fields are required for %s api', 'bit-integrations'), 'Fluent CRM')); } $recordApiHelper = new RecordApiHelper($this->_integrationID); diff --git a/includes/Actions/FluentCommunity/RecordApiHelper.php b/includes/Actions/FluentCommunity/RecordApiHelper.php index 5d25ad3c..df3d7f62 100644 --- a/includes/Actions/FluentCommunity/RecordApiHelper.php +++ b/includes/Actions/FluentCommunity/RecordApiHelper.php @@ -7,7 +7,6 @@ namespace BitCode\FI\Actions\FluentCommunity; use BitCode\FI\Log\LogHandler; -use FluentCrm\App\Models\Subscriber; /** * Provide functionality for Record insert @@ -24,6 +23,8 @@ public function __construct($integId) public function insertRecord($data, $actions) { // Get user ID by email + error_log('data: ' . print_r($data, true)); + $userId = FluentCommunityController::getUserByEmail($data['email']); if (!$userId) { @@ -33,84 +34,33 @@ public function insertRecord($data, $actions) ]; } - // Check if FluentCommunity plugin exists and add user to space - if (class_exists('\FluentCommunity\App\Models\Space')) { + try { $spaceId = $data['space_id']; $memberRole = $data['member_role'] ?? 'member'; + $by = 'by_automation'; - // Add user to FluentCommunity space - $result = \FluentCommunity\App\Models\Space::addMember($spaceId, $userId, $memberRole); + // Use FluentCommunity Helper + if (class_exists('\FluentCommunity\App\Services\Helper')) { + \FluentCommunity\App\Services\Helper::addToSpace($spaceId, $userId, $memberRole, $by); - if ($result) { $response = [ 'success' => true, - 'messages' => __('User added to space successfully!', 'bit-integrations') + 'messages' => __('User added to space successfully!', 'bit-integrations'), + 'space_id' => $spaceId, + 'user_id' => $userId, + 'role' => $memberRole, ]; } else { $response = [ 'success' => false, - 'messages' => __('Failed to add user to space!', 'bit-integrations') + 'messages' => __('FluentCommunity Helper not available!', 'bit-integrations') ]; } - } else { - // Fallback to FluentCRM if FluentCommunity not available - $subscriber = Subscriber::where('email', $data['email'])->first(); - - if ($subscriber && isset($actions->skip_if_exists) && $actions->skip_if_exists) { - $response = [ - 'success' => false, - 'messages' => __('Contact already exists!', 'bit-integrations') - ]; - } else { - if (!$subscriber) { - if (isset($actions->double_opt_in) && $actions->double_opt_in) { - $data['status'] = 'pending'; - } else { - $data['status'] = 'subscribed'; - } - - $subscriber = FluentCrmApi('contacts')->createOrUpdate($data, false, false); - - if ($subscriber->status === 'pending') { - $subscriber->sendDoubleOptinEmail(); - } - if ($subscriber) { - $response = [ - 'success' => true, - 'messages' => __('Insert successfully!', 'bit-integrations') - ]; - } else { - $response = [ - 'success' => false, - 'messages' => __('Something wrong!', 'bit-integrations') - ]; - } - } else { - $hasDouBleOptIn = isset($actions->double_opt_in) && $actions->double_opt_in; - $forceSubscribed = !$hasDouBleOptIn && ($subscriber->status != 'subscribed'); - - if ($forceSubscribed) { - $data['status'] = 'subscribed'; - } - - $subscriber = FluentCrmApi('contacts')->createOrUpdate($data, $forceSubscribed, false); - - if ($hasDouBleOptIn && ($subscriber->status === 'pending' || $subscriber->status === 'unsubscribed')) { - $subscriber->sendDoubleOptinEmail(); - } - if ($subscriber) { - $response = [ - 'success' => true, - 'messages' => __('Insert successfully!', 'bit-integrations') - ]; - } else { - $response = [ - 'success' => false, - 'messages' => __('Something wrong!', 'bit-integrations') - ]; - } - } - } + } catch (Exception $e) { + $response = [ + 'success' => false, + 'messages' => $e->getMessage() + ]; } return $response; @@ -128,48 +78,78 @@ public function removeUser($data) ]; } - // Check if FluentCommunity plugin exists and remove user from space - if (class_exists('\FluentCommunity\App\Models\Space')) { + try { $spaceId = $data['space_id']; + $by = 'by_automation'; - // Remove user from FluentCommunity space - $result = \FluentCommunity\App\Models\Space::removeMember($spaceId, $userId); + // Use FluentCommunity Helper + if (class_exists('\FluentCommunity\App\Services\Helper')) { + \FluentCommunity\App\Services\Helper::removeFromSpace($spaceId, $userId, $by); - if ($result) { $response = [ 'success' => true, - 'messages' => __('User removed from space successfully!', 'bit-integrations') + 'messages' => __('User removed from space successfully!', 'bit-integrations'), + 'space_id' => $spaceId, + 'user_id' => $userId, ]; } else { $response = [ 'success' => false, - 'messages' => __('Failed to remove user from space!', 'bit-integrations') + 'messages' => __('FluentCommunity Helper not available!', 'bit-integrations') ]; } - } else { - // Fallback to FluentCRM if FluentCommunity not available - $subscriber = Subscriber::where('email', $data['email'])->first(); + } catch (Exception $e) { + $response = [ + 'success' => false, + 'messages' => $e->getMessage() + ]; + } + + return $response; + } + + public function addCourse($data) + { + // Get user ID by email + $userId = FluentCommunityController::getUserByEmail($data['email']); + + if (!$userId) { + return [ + 'success' => false, + 'messages' => __('User not found with this email!', 'bit-integrations') + ]; + } + + try { + $courseId = $data['course_id']; - if (!$subscriber) { - return $response = [ + // Use FluentCommunity's CourseHelper::enrollCourse() method + if (class_exists('\FluentCommunity\Modules\Course\Services\CourseHelper')) { + \FluentCommunity\Modules\Course\Services\CourseHelper::enrollCourse($courseId, $userId); + + $response = [ + 'success' => true, + 'messages' => __('User enrolled in course successfully!', 'bit-integrations'), + 'course_id' => $courseId, + 'user_id' => $userId, + ]; + } else { + $response = [ 'success' => false, - 'messages' => __("Contact doesn't exists!", 'bit-integrations') + 'messages' => __('FluentCommunity CourseHelper not available!', 'bit-integrations') ]; } - - $listId = $data['lists']; - $subscriber->detachLists($listId); - + } catch (Exception $e) { $response = [ - 'success' => true, - 'messages' => __('User remove from list successfully!', 'bit-integrations') + 'success' => false, + 'messages' => $e->getMessage() ]; } return $response; } - public function addCourse($data) + public function removeCourse($data) { // Get user ID by email $userId = FluentCommunityController::getUserByEmail($data['email']); @@ -181,27 +161,36 @@ public function addCourse($data) ]; } - $courseId = $data['course_id']; + try { + $courseId = $data['course_id']; - // Use FluentCommunity's CourseHelper::enrollCourse() method (same as Flowmattic) - if (class_exists('\FluentCommunity\Modules\Course\Services\CourseHelper')) { - \FluentCommunity\Modules\Course\Services\CourseHelper::enrollCourse($courseId, $userId); - $response = [ - 'success' => true, - 'messages' => __('User added to course successfully!', 'bit-integrations') - ]; - } else { - // Fallback: If CourseHelper not available, return test mode success + // Use FluentCommunity's CourseHelper::leaveCourse() method + if (class_exists('\FluentCommunity\Modules\Course\Services\CourseHelper')) { + \FluentCommunity\Modules\Course\Services\CourseHelper::leaveCourse($courseId, $userId); + + $response = [ + 'success' => true, + 'messages' => __('User unenrolled from course successfully!', 'bit-integrations'), + 'course_id' => $courseId, + 'user_id' => $userId, + ]; + } else { + $response = [ + 'success' => false, + 'messages' => __('FluentCommunity CourseHelper not available!', 'bit-integrations') + ]; + } + } catch (Exception $e) { $response = [ - 'success' => true, - 'messages' => __('User added to course successfully! (Test mode)', 'bit-integrations') + 'success' => false, + 'messages' => $e->getMessage() ]; } return $response; } - public function removeCourse($data) + public function createPost($data) { // Get user ID by email $userId = FluentCommunityController::getUserByEmail($data['email']); @@ -213,66 +202,167 @@ public function removeCourse($data) ]; } - $courseId = $data['course_id']; + try { + $spaceId = $data['post_space_id']; + $postTitle = $data['post_title']; + $postMessage = $data['post_message']; - // Use FluentCommunity's CourseHelper::leaveCourse() method (same as Flowmattic) - if (class_exists('\FluentCommunity\Modules\Course\Services\CourseHelper')) { - \FluentCommunity\Modules\Course\Services\CourseHelper::leaveCourse($courseId, $userId); - $response = [ - 'success' => true, - 'messages' => __('User removed from course successfully!', 'bit-integrations') + $feedData = [ + 'message' => stripslashes($postMessage), + 'title' => stripslashes($postTitle), + 'space_id' => (int) $spaceId, + 'user_id' => $userId, ]; - } else { - // Fallback: If CourseHelper not available, return test mode success + + // Use FluentCommunity FeedsHelper + if (class_exists('\FluentCommunity\App\Services\FeedsHelper')) { + $feed = \FluentCommunity\App\Services\FeedsHelper::createFeed($feedData); + + if (is_wp_error($feed)) { + $response = [ + 'success' => false, + 'messages' => $feed->get_error_message() + ]; + } else { + $response = [ + 'success' => true, + 'messages' => __('Post created in feed successfully!', 'bit-integrations'), + 'space_id' => $spaceId, + 'user_id' => $userId, + 'feed_id' => $feed->id, + 'title' => $postTitle, + 'feed_url' => $feed->getPermalink(), + ]; + } + } else { + $response = [ + 'success' => false, + 'messages' => __('FluentCommunity FeedsHelper not available!', 'bit-integrations') + ]; + } + } catch (Exception $e) { $response = [ - 'success' => true, - 'messages' => __('User removed from course successfully! (Test mode)', 'bit-integrations') + 'success' => false, + 'messages' => $e->getMessage() ]; } return $response; } - public function createPost($data) + public function createPoll($data) { - $spaceId = $data['post_space_id']; - $userId = $data['post_user_id']; + $spaceId = $data['poll_space_id']; + $userId = FluentCommunityController::getUserByEmail($data['email']); $postTitle = $data['post_title']; $postMessage = $data['post_message']; + $pollOptions = $data['poll_options']; + + if (!$userId) { + return [ + 'success' => false, + 'messages' => __('User not found with this email!', 'bit-integrations') + ]; + } - // Use FluentCommunity's Post model to create a new post - if (class_exists('\FluentCommunity\App\Models\Post')) { - try { - $post = new \FluentCommunity\App\Models\Post(); - $post->title = $postTitle; - $post->content = $postMessage; - $post->user_id = $userId; - $post->space_id = $spaceId; - $post->status = 'published'; - $post->type = 'post'; - $post->save(); + try { + $feedData = [ + 'message' => stripslashes($postMessage), + 'title' => stripslashes($postTitle), + 'space_id' => (int) $spaceId, + 'user_id' => $userId, + 'survey' => 'survey', + ]; - $response = [ - 'success' => true, - 'messages' => __('Post created successfully in FluentCommunity feed!', 'bit-integrations') - ]; - } catch (Exception $e) { + // Use FluentCommunity FeedsHelper + if (class_exists('\FluentCommunity\App\Services\FeedsHelper')) { + $feed = \FluentCommunity\App\Services\FeedsHelper::createFeed($feedData); + + if (is_wp_error($feed)) { + $response = [ + 'success' => false, + 'messages' => $feed->get_error_message() + ]; + } else { + $response = [ + 'success' => true, + 'messages' => __('Poll created in feed successfully!', 'bit-integrations'), + 'space_id' => $spaceId, + 'user_id' => $userId, + 'feed_id' => $feed->id, + 'poll_question' => $postTitle, + 'poll_options' => $pollOptions, + 'feed_url' => $feed->getPermalink(), + ]; + } + } else { $response = [ 'success' => false, - 'messages' => __('Failed to create post: ' . $e->getMessage(), 'bit-integrations') + 'messages' => __('FluentCommunity FeedsHelper not available!', 'bit-integrations') ]; } - } else { - // Fallback: If FluentCommunity Post model not available, return test mode success + } catch (Exception $e) { $response = [ - 'success' => true, - 'messages' => __('Post created successfully! (Test mode)', 'bit-integrations') + 'success' => false, + 'messages' => $e->getMessage() ]; } return $response; } + public function verifyUser($data) + { + $userId = FluentCommunityController::getUserByEmail($data['email']); + + if (!$userId) { + return [ + 'success' => false, + 'messages' => __('User not found with this email!', 'bit-integrations') + ]; + } + + $user = get_user_by('ID', $userId); + if (!$user) { + return [ + 'success' => false, + 'messages' => __('User not found!', 'bit-integrations') + ]; + } + + // Get user spaces + $spaces = []; + if (class_exists('\FluentCommunity\App\Services\Helper')) { + $spaces = \FluentCommunity\App\Services\Helper::getUserSpaces($userId); + } + + // Get user courses + $courses = []; + if (class_exists('\FluentCommunity\Modules\Course\Services\CourseHelper')) { + $course_helper = new \FluentCommunity\Modules\Course\Services\CourseHelper(); + $courses = $course_helper->getUserCourses($userId); + } + + $profile = [ + 'user_id' => $user->ID, + 'user_login' => $user->user_login, + 'user_email' => $user->user_email, + 'display_name' => $user->display_name, + 'first_name' => $user->first_name, + 'last_name' => $user->last_name, + 'user_registered' => $user->user_registered, + 'avatar_url' => get_avatar_url($user->ID), + 'spaces' => $spaces, + 'courses' => $courses, + ]; + + return [ + 'success' => true, + 'messages' => __('User profile verified successfully!', 'bit-integrations'), + 'profile' => $profile, + ]; + } + public function execute($fieldValues, $fieldMap, $actions, $list_id, $tags, $actionName) { $fieldData = apply_filters('fluent_community_assign_company', [], (array) $actions); @@ -310,6 +400,14 @@ public function execute($fieldValues, $fieldMap, $actions, $list_id, $tags, $act $fieldData['post_user_id'] = $actions->post_user_id; } + // Add poll_space_id and poll_options if provided + if (isset($actions->poll_space_id)) { + $fieldData['poll_space_id'] = $actions->poll_space_id; + } + if (isset($actions->poll_options)) { + $fieldData['poll_options'] = $actions->poll_options; + } + switch ($actionName) { case 'add-user': $recordApiResponse = $this->insertRecord($fieldData, $actions); @@ -330,6 +428,14 @@ public function execute($fieldValues, $fieldMap, $actions, $list_id, $tags, $act case 'create-post': $recordApiResponse = $this->createPost($fieldData); + break; + case 'create-poll': + $recordApiResponse = $this->createPoll($fieldData); + + break; + case 'verify-user': + $recordApiResponse = $this->verifyUser($fieldData); + break; } diff --git a/includes/Actions/FluentCommunity/Routes.php b/includes/Actions/FluentCommunity/Routes.php index 72a8c786..fcba9dff 100644 --- a/includes/Actions/FluentCommunity/Routes.php +++ b/includes/Actions/FluentCommunity/Routes.php @@ -9,7 +9,5 @@ Route::post('fluent_community_authorize', [FluentCommunityController::class, 'fluentCommunityAuthorize']); Route::post('refresh_fluent_community_lists', [FluentCommunityController::class, 'fluentCommunityLists']); -Route::post('fluent_community_get_all_company', [FluentCommunityController::class, 'getAllCompany']); -Route::post('fluent_community_member_roles', [FluentCommunityController::class, 'getMemberRoles']); Route::post('refresh_fluent_community_courses', [FluentCommunityController::class, 'fluentCommunityCourses']); Route::post('refresh_fluent_community_users', [FluentCommunityController::class, 'fluentCommunityUsers']); From 48184b92a34fbeef5c8e83cd909f574ba9d5c15e Mon Sep 17 00:00:00 2001 From: emon Date: Tue, 30 Sep 2025 16:33:30 +0600 Subject: [PATCH 06/12] refactor: code improves --- .../FluentCommunityIntegLayout.jsx | 33 ++- .../FluentCommunity/staticData.js | 12 +- .../FluentCommunity/RecordApiHelper.php | 263 +++--------------- 3 files changed, 60 insertions(+), 248 deletions(-) diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx index 818316bf..b7ca7c98 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx @@ -8,6 +8,9 @@ import { } from './FluentCommunityCommonFunc' import FluentCommunityFieldMap from './FluentCommunityFieldMap' import { actions, pollTypes } from './staticData' +import { useRecoilValue } from 'recoil' +import { $btcbi } from '../../../GlobalStates' +import { checkIsPro, getProLabel } from '../../Utilities/ProUtilHelpers' export default function FluentCommunityIntegLayout({ formID, @@ -20,10 +23,13 @@ export default function FluentCommunityIntegLayout({ setLoading, setSnackbar }) { - // Use static data for actions + const btcbi = useRecoilValue($btcbi) + const { isPro } = btcbi + + // Use static data for actions with pro feature labels const action = actions.map(action => ({ value: action.name, - label: action.label + label: checkIsPro(isPro, action.is_pro) ? action.label : getProLabel(action.label) })) const inputHendler = e => { @@ -100,7 +106,10 @@ export default function FluentCommunityIntegLayout({ className="btcd-paper-inp w-5"> {action.map(({ label, value }) => ( - ))} @@ -210,7 +219,8 @@ export default function FluentCommunityIntegLayout({ onChange={e => inputHendler(e)} name="course_id" value={fluentCommunityConf.course_id} - className="btcd-paper-inp w-5"> + className="btcd-paper-inp w-5" + disabled={!isPro}> {fluentCommunityConf?.fluentCommunityCourses && Object.keys(fluentCommunityConf.fluentCommunityCourses).map(courseName => ( @@ -237,7 +247,7 @@ export default function FluentCommunityIntegLayout({ '--tooltip-txt': `'${__('Refresh Courses', 'bit-integrations')}'` }} type="button" - disabled={isLoading}> + disabled={isLoading || !isPro}> ↻
@@ -251,7 +261,8 @@ export default function FluentCommunityIntegLayout({ onChange={e => inputHendler(e)} name="poll_space_id" value={fluentCommunityConf.poll_space_id} - className="btcd-paper-inp w-5"> + className="btcd-paper-inp w-5" + disabled={!isPro}> {fluentCommunityConf?.fluentCommunityList && Object.keys(fluentCommunityConf.fluentCommunityList).map(listName => ( @@ -276,7 +287,7 @@ export default function FluentCommunityIntegLayout({ '--tooltip-txt': `'${__('Refresh Spaces', 'bit-integrations')}'` }} type="button" - disabled={isLoading}> + disabled={isLoading || !isPro}> ↻
@@ -288,7 +299,8 @@ export default function FluentCommunityIntegLayout({ onChange={e => inputHendler(e)} name="poll_options" value={fluentCommunityConf.poll_options} - className="btcd-paper-inp w-5"> + className="btcd-paper-inp w-5" + disabled={!isPro}> {pollTypes.map(type => ( {fluentCommunityConf?.fluentCommunityList && Object.keys(fluentCommunityConf.fluentCommunityList).map(listName => ( @@ -332,7 +345,7 @@ export default function FluentCommunityIntegLayout({ '--tooltip-txt': `'${__('Refresh Spaces', 'bit-integrations')}'` }} type="button" - disabled={isLoading}> + disabled={isLoading || !isPro}> ↻ diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js b/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js index 7bc3aead..e56ffe5e 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js @@ -10,32 +10,32 @@ export const actions = [ { name: 'remove-user', label: __('Remove user from space', 'bit-integrations'), - is_pro: false + is_pro: true }, { name: 'add-course', label: __('Add user to course', 'bit-integrations'), - is_pro: false + is_pro: true }, { name: 'remove-course', label: __('Remove user from course', 'bit-integrations'), - is_pro: false + is_pro: true }, { name: 'create-post', label: __('Create new post in feed', 'bit-integrations'), - is_pro: false + is_pro: true }, { name: 'create-poll', label: __('Create poll in feed', 'bit-integrations'), - is_pro: false + is_pro: true }, { name: 'verify-user', label: __('Verify user profile', 'bit-integrations'), - is_pro: false + is_pro: true } ] diff --git a/includes/Actions/FluentCommunity/RecordApiHelper.php b/includes/Actions/FluentCommunity/RecordApiHelper.php index df3d7f62..ad2e53b8 100644 --- a/includes/Actions/FluentCommunity/RecordApiHelper.php +++ b/includes/Actions/FluentCommunity/RecordApiHelper.php @@ -68,40 +68,14 @@ public function insertRecord($data, $actions) public function removeUser($data) { - // Get user ID by email - $userId = FluentCommunityController::getUserByEmail($data['email']); + // Use pro hook if available + $response = apply_filters('btcbi_fluent_community_remove_user', $data); - if (!$userId) { + if ($response === $data) { + // Pro feature not available return [ 'success' => false, - 'messages' => __('User not found with this email!', 'bit-integrations') - ]; - } - - try { - $spaceId = $data['space_id']; - $by = 'by_automation'; - - // Use FluentCommunity Helper - if (class_exists('\FluentCommunity\App\Services\Helper')) { - \FluentCommunity\App\Services\Helper::removeFromSpace($spaceId, $userId, $by); - - $response = [ - 'success' => true, - 'messages' => __('User removed from space successfully!', 'bit-integrations'), - 'space_id' => $spaceId, - 'user_id' => $userId, - ]; - } else { - $response = [ - 'success' => false, - 'messages' => __('FluentCommunity Helper not available!', 'bit-integrations') - ]; - } - } catch (Exception $e) { - $response = [ - 'success' => false, - 'messages' => $e->getMessage() + 'messages' => __('This feature is available in Pro version only!', 'bit-integrations') ]; } @@ -110,39 +84,14 @@ public function removeUser($data) public function addCourse($data) { - // Get user ID by email - $userId = FluentCommunityController::getUserByEmail($data['email']); + // Use pro hook if available + $response = apply_filters('btcbi_fluent_community_add_course', $data); - if (!$userId) { + if ($response === $data) { + // Pro feature not available return [ 'success' => false, - 'messages' => __('User not found with this email!', 'bit-integrations') - ]; - } - - try { - $courseId = $data['course_id']; - - // Use FluentCommunity's CourseHelper::enrollCourse() method - if (class_exists('\FluentCommunity\Modules\Course\Services\CourseHelper')) { - \FluentCommunity\Modules\Course\Services\CourseHelper::enrollCourse($courseId, $userId); - - $response = [ - 'success' => true, - 'messages' => __('User enrolled in course successfully!', 'bit-integrations'), - 'course_id' => $courseId, - 'user_id' => $userId, - ]; - } else { - $response = [ - 'success' => false, - 'messages' => __('FluentCommunity CourseHelper not available!', 'bit-integrations') - ]; - } - } catch (Exception $e) { - $response = [ - 'success' => false, - 'messages' => $e->getMessage() + 'messages' => __('This feature is available in Pro version only!', 'bit-integrations') ]; } @@ -151,39 +100,14 @@ public function addCourse($data) public function removeCourse($data) { - // Get user ID by email - $userId = FluentCommunityController::getUserByEmail($data['email']); + // Use pro hook if available + $response = apply_filters('btcbi_fluent_community_remove_course', $data); - if (!$userId) { + if ($response === $data) { + // Pro feature not available return [ 'success' => false, - 'messages' => __('User not found with this email!', 'bit-integrations') - ]; - } - - try { - $courseId = $data['course_id']; - - // Use FluentCommunity's CourseHelper::leaveCourse() method - if (class_exists('\FluentCommunity\Modules\Course\Services\CourseHelper')) { - \FluentCommunity\Modules\Course\Services\CourseHelper::leaveCourse($courseId, $userId); - - $response = [ - 'success' => true, - 'messages' => __('User unenrolled from course successfully!', 'bit-integrations'), - 'course_id' => $courseId, - 'user_id' => $userId, - ]; - } else { - $response = [ - 'success' => false, - 'messages' => __('FluentCommunity CourseHelper not available!', 'bit-integrations') - ]; - } - } catch (Exception $e) { - $response = [ - 'success' => false, - 'messages' => $e->getMessage() + 'messages' => __('This feature is available in Pro version only!', 'bit-integrations') ]; } @@ -192,58 +116,14 @@ public function removeCourse($data) public function createPost($data) { - // Get user ID by email - $userId = FluentCommunityController::getUserByEmail($data['email']); + // Use pro hook if available + $response = apply_filters('btcbi_fluent_community_create_post', $data); - if (!$userId) { + if ($response === $data) { + // Pro feature not available return [ 'success' => false, - 'messages' => __('User not found with this email!', 'bit-integrations') - ]; - } - - try { - $spaceId = $data['post_space_id']; - $postTitle = $data['post_title']; - $postMessage = $data['post_message']; - - $feedData = [ - 'message' => stripslashes($postMessage), - 'title' => stripslashes($postTitle), - 'space_id' => (int) $spaceId, - 'user_id' => $userId, - ]; - - // Use FluentCommunity FeedsHelper - if (class_exists('\FluentCommunity\App\Services\FeedsHelper')) { - $feed = \FluentCommunity\App\Services\FeedsHelper::createFeed($feedData); - - if (is_wp_error($feed)) { - $response = [ - 'success' => false, - 'messages' => $feed->get_error_message() - ]; - } else { - $response = [ - 'success' => true, - 'messages' => __('Post created in feed successfully!', 'bit-integrations'), - 'space_id' => $spaceId, - 'user_id' => $userId, - 'feed_id' => $feed->id, - 'title' => $postTitle, - 'feed_url' => $feed->getPermalink(), - ]; - } - } else { - $response = [ - 'success' => false, - 'messages' => __('FluentCommunity FeedsHelper not available!', 'bit-integrations') - ]; - } - } catch (Exception $e) { - $response = [ - 'success' => false, - 'messages' => $e->getMessage() + 'messages' => __('This feature is available in Pro version only!', 'bit-integrations') ]; } @@ -252,59 +132,14 @@ public function createPost($data) public function createPoll($data) { - $spaceId = $data['poll_space_id']; - $userId = FluentCommunityController::getUserByEmail($data['email']); - $postTitle = $data['post_title']; - $postMessage = $data['post_message']; - $pollOptions = $data['poll_options']; + // Use pro hook if available + $response = apply_filters('btcbi_fluent_community_create_poll', $data); - if (!$userId) { + if ($response === $data) { + // Pro feature not available return [ 'success' => false, - 'messages' => __('User not found with this email!', 'bit-integrations') - ]; - } - - try { - $feedData = [ - 'message' => stripslashes($postMessage), - 'title' => stripslashes($postTitle), - 'space_id' => (int) $spaceId, - 'user_id' => $userId, - 'survey' => 'survey', - ]; - - // Use FluentCommunity FeedsHelper - if (class_exists('\FluentCommunity\App\Services\FeedsHelper')) { - $feed = \FluentCommunity\App\Services\FeedsHelper::createFeed($feedData); - - if (is_wp_error($feed)) { - $response = [ - 'success' => false, - 'messages' => $feed->get_error_message() - ]; - } else { - $response = [ - 'success' => true, - 'messages' => __('Poll created in feed successfully!', 'bit-integrations'), - 'space_id' => $spaceId, - 'user_id' => $userId, - 'feed_id' => $feed->id, - 'poll_question' => $postTitle, - 'poll_options' => $pollOptions, - 'feed_url' => $feed->getPermalink(), - ]; - } - } else { - $response = [ - 'success' => false, - 'messages' => __('FluentCommunity FeedsHelper not available!', 'bit-integrations') - ]; - } - } catch (Exception $e) { - $response = [ - 'success' => false, - 'messages' => $e->getMessage() + 'messages' => __('This feature is available in Pro version only!', 'bit-integrations') ]; } @@ -313,54 +148,18 @@ public function createPoll($data) public function verifyUser($data) { - $userId = FluentCommunityController::getUserByEmail($data['email']); + // Use pro hook if available + $response = apply_filters('btcbi_fluent_community_verify_user', $data); - if (!$userId) { + if ($response === $data) { + // Pro feature not available return [ 'success' => false, - 'messages' => __('User not found with this email!', 'bit-integrations') + 'messages' => __('This feature is available in Pro version only!', 'bit-integrations') ]; } - $user = get_user_by('ID', $userId); - if (!$user) { - return [ - 'success' => false, - 'messages' => __('User not found!', 'bit-integrations') - ]; - } - - // Get user spaces - $spaces = []; - if (class_exists('\FluentCommunity\App\Services\Helper')) { - $spaces = \FluentCommunity\App\Services\Helper::getUserSpaces($userId); - } - - // Get user courses - $courses = []; - if (class_exists('\FluentCommunity\Modules\Course\Services\CourseHelper')) { - $course_helper = new \FluentCommunity\Modules\Course\Services\CourseHelper(); - $courses = $course_helper->getUserCourses($userId); - } - - $profile = [ - 'user_id' => $user->ID, - 'user_login' => $user->user_login, - 'user_email' => $user->user_email, - 'display_name' => $user->display_name, - 'first_name' => $user->first_name, - 'last_name' => $user->last_name, - 'user_registered' => $user->user_registered, - 'avatar_url' => get_avatar_url($user->ID), - 'spaces' => $spaces, - 'courses' => $courses, - ]; - - return [ - 'success' => true, - 'messages' => __('User profile verified successfully!', 'bit-integrations'), - 'profile' => $profile, - ]; + return $response; } public function execute($fieldValues, $fieldMap, $actions, $list_id, $tags, $actionName) From 8314a399a946efc6d07169be831cc79486e2b55f Mon Sep 17 00:00:00 2001 From: emon Date: Tue, 30 Sep 2025 17:27:24 +0600 Subject: [PATCH 07/12] refactor: code changes --- .../FluentCommunity/FluentCommunityIntegLayout.jsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx index b7ca7c98..9e184e3f 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx @@ -29,7 +29,8 @@ export default function FluentCommunityIntegLayout({ // Use static data for actions with pro feature labels const action = actions.map(action => ({ value: action.name, - label: checkIsPro(isPro, action.is_pro) ? action.label : getProLabel(action.label) + label: checkIsPro(isPro, action.is_pro) ? action.label : getProLabel(action.label), + is_pro: action.is_pro })) const inputHendler = e => { @@ -105,11 +106,8 @@ export default function FluentCommunityIntegLayout({ value={fluentCommunityConf?.actionName} className="btcd-paper-inp w-5"> - {action.map(({ label, value }) => ( - ))} From 8a1123edae34312fdb792130d2ac02fef8a956ed Mon Sep 17 00:00:00 2001 From: emon Date: Wed, 1 Oct 2025 12:10:29 +0600 Subject: [PATCH 08/12] refactor: add edit behavior of fluent community --- .../components/AllIntegrations/EditInteg.jsx | 3 + .../FluentCommunity/EditFluentCommunity.jsx | 92 +++++++++++++++++++ .../FluentCommunityIntegLayout.jsx | 2 +- 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 frontend-dev/src/components/AllIntegrations/FluentCommunity/EditFluentCommunity.jsx diff --git a/frontend-dev/src/components/AllIntegrations/EditInteg.jsx b/frontend-dev/src/components/AllIntegrations/EditInteg.jsx index 4b1de084..be46b418 100644 --- a/frontend-dev/src/components/AllIntegrations/EditInteg.jsx +++ b/frontend-dev/src/components/AllIntegrations/EditInteg.jsx @@ -32,6 +32,7 @@ const EditZohoFlow = lazy(() => import('./ZohoFlow/EditZohoFlow')) const EditTelegram = lazy(() => import('./Telegram/EditTelegram')) const EditTutorLms = lazy(() => import('./TutorLms/EditTutorLms')) const EditFluentCrm = lazy(() => import('./FluentCRM/EditFluentCrm')) +const EditFluentCommunity = lazy(() => import('./FluentCommunity/EditFluentCommunity')) const EditEncharge = lazy(() => import('./Encharge/EditEncharge')) const EditAutonami = lazy(() => import('./Autonami/EditAutonami')) const EditDropbox = lazy(() => import('./Dropbox/EditDropbox')) @@ -303,6 +304,8 @@ const IntegType = memo(({ allIntegURL, flow }) => { return case 'Fluent Crm': return + case 'Fluent Community': + return case 'Encharge': return case 'Registration': diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/EditFluentCommunity.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/EditFluentCommunity.jsx new file mode 100644 index 00000000..0d7ce329 --- /dev/null +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/EditFluentCommunity.jsx @@ -0,0 +1,92 @@ +/* eslint-disable no-param-reassign */ + +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 EditFormInteg from '../EditFormInteg' +import SetEditIntegComponents from '../IntegrationHelpers/SetEditIntegComponents' +import EditWebhookInteg from '../EditWebhookInteg' +import { saveActionConf } from '../IntegrationHelpers/IntegrationHelpers' +import IntegrationStepThree from '../IntegrationHelpers/IntegrationStepThree' +import { handleInput, checkMappedFields } from './FluentCommunityCommonFunc' +import FluentCommunityIntegLayout from './FluentCommunityIntegLayout' + +function EditFluentCommunity({ allIntegURL }) { + const navigate = useNavigate() + const { id, formID } = useParams() + + const [fluentCommunityConf, setFluentCommunityConf] = useRecoilState($actionConf) + const [flow, setFlow] = useRecoilState($newFlow) + const formFields = useRecoilValue($formFields) + const [isLoading, setIsLoading] = useState(false) + const [loading, setLoading] = useState({}) + const [snack, setSnackbar] = useState({ show: false }) + const saveConfig = () => { + if (!checkMappedFields(fluentCommunityConf)) { + setSnackbar({ + show: true, + msg: __('Please map all required fields to continue.', 'bit-integrations') + }) + return + } + saveActionConf({ + flow, + setFlow, + allIntegURL, + conf: fluentCommunityConf, + navigate, + edit: 1, + setIsLoading, + setSnackbar + }) + } + + return ( +
+ + +
+ {__('Integration Name:', 'bit-integrations')} + handleInput(e, fluentCommunityConf, setFluentCommunityConf)} + name="name" + value={fluentCommunityConf.name} + type="text" + placeholder={__('Integration Name...', 'bit-integrations')} + /> +
+
+ + + + + +
+
+ ) +} + +export default EditFluentCommunity diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx index 9e184e3f..0fe48a0e 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx @@ -24,7 +24,7 @@ export default function FluentCommunityIntegLayout({ setSnackbar }) { const btcbi = useRecoilValue($btcbi) - const { isPro } = btcbi + const { isPro } = true //btcbi // Use static data for actions with pro feature labels const action = actions.map(action => ({ From 6f658f87b764ddd6a16948466ada4150b2d715da Mon Sep 17 00:00:00 2001 From: emon Date: Sun, 5 Oct 2025 13:20:24 +0600 Subject: [PATCH 09/12] refactor: code improves --- .../FluentCommunity/FluentCommunityIntegLayout.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx index 0fe48a0e..9e184e3f 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx @@ -24,7 +24,7 @@ export default function FluentCommunityIntegLayout({ setSnackbar }) { const btcbi = useRecoilValue($btcbi) - const { isPro } = true //btcbi + const { isPro } = btcbi // Use static data for actions with pro feature labels const action = actions.map(action => ({ From 6f98db22e99800ff5dfcd19eff5d9046e1693658 Mon Sep 17 00:00:00 2001 From: emon Date: Tue, 7 Oct 2025 12:55:54 +0600 Subject: [PATCH 10/12] refactor: remove print statement and issues --- .../FluentCommunity/FluentCommunityAuthorization.jsx | 1 - includes/Actions/FluentCommunity/FluentCommunityController.php | 3 +-- includes/Actions/FluentCommunity/RecordApiHelper.php | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityAuthorization.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityAuthorization.jsx index 1f41ffeb..9ed6f2f1 100644 --- a/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityAuthorization.jsx +++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityAuthorization.jsx @@ -30,7 +30,6 @@ export default function FluentCommunityAuthorization({ ) const handleAuthorize = () => { - console.log('check it::') setIsLoading('auth') bitsFetch({}, 'fluent_community_authorize').then(result => { if (isMounted) { diff --git a/includes/Actions/FluentCommunity/FluentCommunityController.php b/includes/Actions/FluentCommunity/FluentCommunityController.php index 1087fe18..d3cc8fd5 100644 --- a/includes/Actions/FluentCommunity/FluentCommunityController.php +++ b/includes/Actions/FluentCommunity/FluentCommunityController.php @@ -178,7 +178,6 @@ public static function fluentCommunityUsers() public static function getUserByEmail($email) { $user = get_user_by('email', $email); - error_log('user: ' . $email . print_r($user, true)); if ($user) { return $user->ID; @@ -215,7 +214,7 @@ public function execute($integrationData, $fieldValues) $actionName = $integrationDetails->actionName; if (empty($fieldMap)) { - return new WP_Error('REQ_FIELD_EMPTY', wp_sprintf(__('module, fields are required for %s api', 'bit-integrations'), 'Fluent CRM')); + return new WP_Error('REQ_FIELD_EMPTY', wp_sprintf(__('module, fields are required for %s api', 'bit-integrations'), 'Fluent Community')); } $recordApiHelper = new RecordApiHelper($this->_integrationID); diff --git a/includes/Actions/FluentCommunity/RecordApiHelper.php b/includes/Actions/FluentCommunity/RecordApiHelper.php index ad2e53b8..f7ec4821 100644 --- a/includes/Actions/FluentCommunity/RecordApiHelper.php +++ b/includes/Actions/FluentCommunity/RecordApiHelper.php @@ -7,6 +7,7 @@ namespace BitCode\FI\Actions\FluentCommunity; use BitCode\FI\Log\LogHandler; +use Exception; /** * Provide functionality for Record insert @@ -23,7 +24,6 @@ public function __construct($integId) public function insertRecord($data, $actions) { // Get user ID by email - error_log('data: ' . print_r($data, true)); $userId = FluentCommunityController::getUserByEmail($data['email']); From ab96241056dc7eefd9f2e023f75ab46dae287ad2 Mon Sep 17 00:00:00 2001 From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com> Date: Mon, 13 Oct 2025 12:14:16 +0600 Subject: [PATCH 11/12] feat: fluentCart triggers added --- .../src/Utils/StaticData/webhookIntegrations.js | 3 ++- .../src/resource/img/integ/fluentCart.webp | Bin 0 -> 5568 bytes includes/Core/Util/AllTriggersName.php | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 frontend-dev/src/resource/img/integ/fluentCart.webp diff --git a/frontend-dev/src/Utils/StaticData/webhookIntegrations.js b/frontend-dev/src/Utils/StaticData/webhookIntegrations.js index 42cde393..2a90e9f3 100644 --- a/frontend-dev/src/Utils/StaticData/webhookIntegrations.js +++ b/frontend-dev/src/Utils/StaticData/webhookIntegrations.js @@ -74,7 +74,8 @@ export const customFormIntegrations = [ 'EasyCommerce', 'FormGent', 'GeoDirectory', - 'StoreEngine' + 'StoreEngine', + 'FluentCart' ] export const actionHookIntegrations = ['ActionHook'] diff --git a/frontend-dev/src/resource/img/integ/fluentCart.webp b/frontend-dev/src/resource/img/integ/fluentCart.webp new file mode 100644 index 0000000000000000000000000000000000000000..10a384ec027ae28af0517368a4a73ff96450da55 GIT binary patch literal 5568 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 x<;7sAp?res)b7XQcBWrjb6G-}zx1`UaQ ['name' => 'Fluent Forms', 'isPro' => true, 'is_active' => false], 'FluentBoards' => ['name' => 'Fluent Boards', 'isPro' => true, 'is_active' => false], 'FluentBooking' => ['name' => 'Fluent Booking', 'isPro' => true, 'is_active' => false], + 'FluentCart' => ['name' => 'FluentCart', 'isPro' => true, 'is_active' => false], 'FluentCrm' => ['name' => 'Fluent CRM', 'isPro' => true, 'is_active' => false], 'FluentCommunity' => ['name' => 'Fluent Community', 'isPro' => true, 'is_active' => false], 'FluentSupport' => ['name' => 'Fluent Support', 'isPro' => true, 'is_active' => false], From f5808caf1daa01b4b102e0a91de2b9fb304c6109 Mon Sep 17 00:00:00 2001 From: Rishad Alam <101513331+RishadAlam@users.noreply.github.com> Date: Mon, 13 Oct 2025 12:14:51 +0600 Subject: [PATCH 12/12] Revert "feat: fluentCart triggers added" This reverts commit ab96241056dc7eefd9f2e023f75ab46dae287ad2. --- .../src/Utils/StaticData/webhookIntegrations.js | 3 +-- .../src/resource/img/integ/fluentCart.webp | Bin 5568 -> 0 bytes includes/Core/Util/AllTriggersName.php | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 frontend-dev/src/resource/img/integ/fluentCart.webp diff --git a/frontend-dev/src/Utils/StaticData/webhookIntegrations.js b/frontend-dev/src/Utils/StaticData/webhookIntegrations.js index 2a90e9f3..42cde393 100644 --- a/frontend-dev/src/Utils/StaticData/webhookIntegrations.js +++ b/frontend-dev/src/Utils/StaticData/webhookIntegrations.js @@ -74,8 +74,7 @@ export const customFormIntegrations = [ 'EasyCommerce', 'FormGent', 'GeoDirectory', - 'StoreEngine', - 'FluentCart' + 'StoreEngine' ] export const actionHookIntegrations = ['ActionHook'] diff --git a/frontend-dev/src/resource/img/integ/fluentCart.webp b/frontend-dev/src/resource/img/integ/fluentCart.webp deleted file mode 100644 index 10a384ec027ae28af0517368a4a73ff96450da55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5568 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 x<;7sAp?res)b7XQcBWrjb6G-}zx1`UaQ ['name' => 'Fluent Forms', 'isPro' => true, 'is_active' => false], 'FluentBoards' => ['name' => 'Fluent Boards', 'isPro' => true, 'is_active' => false], 'FluentBooking' => ['name' => 'Fluent Booking', 'isPro' => true, 'is_active' => false], - 'FluentCart' => ['name' => 'FluentCart', 'isPro' => true, 'is_active' => false], 'FluentCrm' => ['name' => 'Fluent CRM', 'isPro' => true, 'is_active' => false], 'FluentCommunity' => ['name' => 'Fluent Community', 'isPro' => true, 'is_active' => false], 'FluentSupport' => ['name' => 'Fluent Support', 'isPro' => true, 'is_active' => false],