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/FluentCommunity.jsx b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunity.jsx
new file mode 100644
index 00000000..fbffc95f
--- /dev/null
+++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunity.jsx
@@ -0,0 +1,145 @@
+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) {
+ // All actions need field mapping validation
+ 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..9ed6f2f1
--- /dev/null
+++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityAuthorization.jsx
@@ -0,0 +1,115 @@
+/* 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 = () => {
+ 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..d9fa5f35
--- /dev/null
+++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityCommonFunc.js
@@ -0,0 +1,268 @@
+import { __ } from '../../../Utils/i18nwrap'
+import bitsFetch from '../../../Utils/bitsFetch'
+import { create } from 'mutative'
+import { actionFields, memberRoles } from './staticData'
+
+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)
+
+ // Get fields from static data based on action
+ const actionName = fluentCommunityConf?.actionName || ''
+ const fields = actionFields[actionName] || []
+
+ 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
+ }
+ })
+
+ setFluentCommunityConf(prevConf =>
+ create(prevConf, newConf => {
+ newConf.fluentCommunityFields = fluentCommunityFields
+ 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 for this action', 'bit-integrations')
+ })
+ }
+
+ setIsLoading(false)
+}
+
+export const refreshMemberRoles = (
+ fluentCommunityConf,
+ setFluentCommunityConf,
+ loading,
+ setLoading,
+ setSnackbar
+) => {
+ setLoading({ ...loading, memberRoles: true })
+
+ // Use static member roles data
+ setFluentCommunityConf(prevConf =>
+ create(prevConf, newConf => {
+ newConf.memberRoles = memberRoles
+ })
+ )
+
+ setSnackbar({
+ show: true,
+ msg: __('FluentCommunity member roles refreshed', 'bit-integrations')
+ })
+
+ 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 { fluentCommunityFields } = fluentCommunityConf
+ const required = Object.values(fluentCommunityFields)
+ .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 = fluentCommunityFields[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..97a12058
--- /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?.fluentCommunityFields &&
+ Object.values(fluentCommunityConf?.fluentCommunityFields).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..9e184e3f
--- /dev/null
+++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/FluentCommunityIntegLayout.jsx
@@ -0,0 +1,391 @@
+import { __ } from '../../../Utils/i18nwrap'
+import Loader from '../../Loaders/Loader'
+import {
+ refreshCommunityList,
+ refreshFluentCommunityHeader,
+ refreshMemberRoles,
+ refreshCourseList
+} 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,
+ formFields,
+ fluentCommunityConf,
+ setFluentCommunityConf,
+ isLoading,
+ setIsLoading,
+ loading,
+ setLoading,
+ setSnackbar
+}) {
+ 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: checkIsPro(isPro, action.is_pro) ? action.label : getProLabel(action.label),
+ is_pro: action.is_pro
+ }))
+
+ 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
+ } 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 })
+ }
+
+ 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
+
+ // Clear existing field mapping and fields when switching actions
+ newConf.field_map = []
+ newConf.fluentCommunityFields = {}
+
+ // First set the action name
+ setFluentCommunityConf(newConf)
+
+ // Then refresh fields with the updated action name
+ 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)
+ }
+ if (value === 'create-poll') {
+ refreshCommunityList(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-poll' &&
+ fluentCommunityConf?.fluentCommunityList &&
+ !loading.fluentCommunityList && (
+
+ {__('Space:', 'bit-integrations')}
+
+
+
+ )}
+ {fluentCommunityConf?.actionName === 'create-poll' && (
+
+ {__('Poll Type:', 'bit-integrations')}
+
+
+ )}
+ {fluentCommunityConf?.actionName === 'create-post' &&
+ fluentCommunityConf?.fluentCommunityList &&
+ !loading.fluentCommunityList && (
+
+ {__('Space:', '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) => (
+
+ ))}
+ >
+ )}
+ >
+ )
+}
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..e56ffe5e
--- /dev/null
+++ b/frontend-dev/src/components/AllIntegrations/FluentCommunity/staticData.js
@@ -0,0 +1,77 @@
+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: true
+ },
+ {
+ name: 'add-course',
+ label: __('Add user to course', 'bit-integrations'),
+ is_pro: true
+ },
+ {
+ name: 'remove-course',
+ label: __('Remove user from course', 'bit-integrations'),
+ is_pro: true
+ },
+ {
+ name: 'create-post',
+ label: __('Create new post in feed', 'bit-integrations'),
+ is_pro: true
+ },
+ {
+ name: 'create-poll',
+ label: __('Create poll in feed', 'bit-integrations'),
+ is_pro: true
+ },
+ {
+ name: 'verify-user',
+ label: __('Verify user profile', 'bit-integrations'),
+ is_pro: true
+ }
+]
+
+// 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 }
+ ],
+ // 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
+export const memberRoles = [
+ { id: 'member', title: __('Member', 'bit-integrations') },
+ { 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/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);
+ }
+
+ /**
+ * Fetch Community courses
+ *
+ * @return Fluent Community courses
+ */
+ public static function fluentCommunityCourses()
+ {
+ self::checkedExistsFluentCommunity();
+
+ $fluentCommunityCourses = [];
+
+ // Use FluentCommunity's Utility::getCourses() method
+ 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) {
+ if (\is_object($course) && method_exists($course, 'getAttributes')) {
+ // Eloquent model
+ if (isset($course->title, $course->id)) {
+ $fluentCommunityCourses[$course->title] = (object) [
+ 'id' => $course->id,
+ 'title' => $course->title
+ ];
+ } else {
+ $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']
+ ];
+ }
+ }
+ }
+ }
+
+ $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);
+ }
+
+ /**
+ * 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..f7ec4821
--- /dev/null
+++ b/includes/Actions/FluentCommunity/RecordApiHelper.php
@@ -0,0 +1,249 @@
+_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')
+ ];
+ }
+
+ try {
+ $spaceId = $data['space_id'];
+ $memberRole = $data['member_role'] ?? 'member';
+ $by = 'by_automation';
+
+ // Use FluentCommunity Helper
+ if (class_exists('\FluentCommunity\App\Services\Helper')) {
+ \FluentCommunity\App\Services\Helper::addToSpace($spaceId, $userId, $memberRole, $by);
+
+ $response = [
+ 'success' => true,
+ 'messages' => __('User added to space successfully!', 'bit-integrations'),
+ 'space_id' => $spaceId,
+ 'user_id' => $userId,
+ 'role' => $memberRole,
+ ];
+ } else {
+ $response = [
+ 'success' => false,
+ 'messages' => __('FluentCommunity Helper not available!', 'bit-integrations')
+ ];
+ }
+ } catch (Exception $e) {
+ $response = [
+ 'success' => false,
+ 'messages' => $e->getMessage()
+ ];
+ }
+
+ return $response;
+ }
+
+ public function removeUser($data)
+ {
+ // Use pro hook if available
+ $response = apply_filters('btcbi_fluent_community_remove_user', $data);
+
+ if ($response === $data) {
+ // Pro feature not available
+ return [
+ 'success' => false,
+ 'messages' => __('This feature is available in Pro version only!', 'bit-integrations')
+ ];
+ }
+
+ return $response;
+ }
+
+ public function addCourse($data)
+ {
+ // Use pro hook if available
+ $response = apply_filters('btcbi_fluent_community_add_course', $data);
+
+ if ($response === $data) {
+ // Pro feature not available
+ return [
+ 'success' => false,
+ 'messages' => __('This feature is available in Pro version only!', 'bit-integrations')
+ ];
+ }
+
+ return $response;
+ }
+
+ public function removeCourse($data)
+ {
+ // Use pro hook if available
+ $response = apply_filters('btcbi_fluent_community_remove_course', $data);
+
+ if ($response === $data) {
+ // Pro feature not available
+ return [
+ 'success' => false,
+ 'messages' => __('This feature is available in Pro version only!', 'bit-integrations')
+ ];
+ }
+
+ return $response;
+ }
+
+ public function createPost($data)
+ {
+ // Use pro hook if available
+ $response = apply_filters('btcbi_fluent_community_create_post', $data);
+
+ if ($response === $data) {
+ // Pro feature not available
+ return [
+ 'success' => false,
+ 'messages' => __('This feature is available in Pro version only!', 'bit-integrations')
+ ];
+ }
+
+ return $response;
+ }
+
+ public function createPoll($data)
+ {
+ // Use pro hook if available
+ $response = apply_filters('btcbi_fluent_community_create_poll', $data);
+
+ if ($response === $data) {
+ // Pro feature not available
+ return [
+ 'success' => false,
+ 'messages' => __('This feature is available in Pro version only!', 'bit-integrations')
+ ];
+ }
+
+ return $response;
+ }
+
+ public function verifyUser($data)
+ {
+ // Use pro hook if available
+ $response = apply_filters('btcbi_fluent_community_verify_user', $data);
+
+ if ($response === $data) {
+ // Pro feature not available
+ return [
+ 'success' => false,
+ 'messages' => __('This feature is available in Pro version only!', '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;
+ }
+
+ // 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);
+
+ 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;
+ case 'create-poll':
+ $recordApiResponse = $this->createPoll($fieldData);
+
+ break;
+ case 'verify-user':
+ $recordApiResponse = $this->verifyUser($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..fcba9dff
--- /dev/null
+++ b/includes/Actions/FluentCommunity/Routes.php
@@ -0,0 +1,13 @@
+