diff --git a/.github/build b/.github/build index 9205a630..b098b977 100755 --- a/.github/build +++ b/.github/build @@ -17,7 +17,6 @@ cd "$PLUGIN_DIR" && pnpm pda cp -r "$PLUGIN_DIR/assets" "$BUILD_DIR/assets" cp -r "$PLUGIN_DIR/bitwpfi.php" "$BUILD_DIR/bitwpfi.php" -cp -r "$PLUGIN_DIR/build-hash.txt" "$BUILD_DIR/build-hash.txt" cp -r "$PLUGIN_DIR/composer.json" "$BUILD_DIR/composer.json" cp -r "$PLUGIN_DIR/backend" "$BUILD_DIR/backend" cp -r "$PLUGIN_DIR/languages" "$BUILD_DIR/languages" diff --git a/.github/workflows/plugin-check.yml b/.github/workflows/plugin-check.yml index f2988362..bcae269d 100644 --- a/.github/workflows/plugin-check.yml +++ b/.github/workflows/plugin-check.yml @@ -67,8 +67,7 @@ jobs: - name: Build plugin run: | - pnpm build - bash .github/copy-assets + bash .github/build - name: WordPress Plugin Check uses: wordpress/plugin-check-action@v1 @@ -86,7 +85,6 @@ jobs: checks: | i18n_usage late_escaping - plugin_header plugin_readme file_type performant_wp_query_params diff --git a/backend/Actions/CreatorLms/CreatorLmsController.php b/backend/Actions/CreatorLms/CreatorLmsController.php new file mode 100644 index 00000000..06d7b086 --- /dev/null +++ b/backend/Actions/CreatorLms/CreatorLmsController.php @@ -0,0 +1,50 @@ +flow_details; + $integId = $integrationData->id; + $fieldMap = $integrationDetails->field_map; + $utilities = isset($integrationDetails->utilities) ? $integrationDetails->utilities : []; + + if (empty($fieldMap)) { + return new WP_Error('field_map_empty', __('Field map is empty', 'bit-integrations')); + } + + $recordApiHelper = new RecordApiHelper($integrationDetails, $integId); + + return $recordApiHelper->execute($fieldValues, $fieldMap, $utilities); + } +} diff --git a/backend/Actions/CreatorLms/RecordApiHelper.php b/backend/Actions/CreatorLms/RecordApiHelper.php new file mode 100644 index 00000000..71a4b955 --- /dev/null +++ b/backend/Actions/CreatorLms/RecordApiHelper.php @@ -0,0 +1,106 @@ +_integrationDetails = $integrationDetails; + $this->_integrationID = $integId; + } + + public function execute($fieldValues, $fieldMap, $utilities) + { + if (!class_exists('CreatorLms') || !\function_exists('crlms_get_course')) { + return [ + 'success' => false, + 'message' => __('Creator LMS is not installed or activated', 'bit-integrations') + ]; + } + + $fieldData = $this->generateReqDataFromFieldMap($fieldMap, $fieldValues); + $mainAction = $this->_integrationDetails->mainAction ?? 'create_student'; + + $defaultResponse = [ + 'success' => false, + // translators: %s is replaced with the plugin name "Bit Integrations Pro" + 'message' => wp_sprintf(__('%s plugin is not installed or activated', 'bit-integrations'), 'Bit Integrations Pro') + ]; + + switch ($mainAction) { + case 'create_student': + $response = Hooks::apply(Config::withPrefix('creator_lms_create_student'), $defaultResponse, $fieldData); + $type = 'student'; + $actionType = 'create_student'; + + break; + case 'update_student_data': + $response = Hooks::apply(Config::withPrefix('creator_lms_update_student_data'), $defaultResponse, $fieldData); + $type = 'student'; + $actionType = 'update_student_data'; + + break; + case 'enroll_user_in_course': + $response = Hooks::apply(Config::withPrefix('creator_lms_enroll_user_in_course'), $defaultResponse, $fieldData); + $type = 'enrollment'; + $actionType = 'enroll_user_in_course'; + + break; + case 'create_course': + $response = Hooks::apply(Config::withPrefix('creator_lms_create_course'), $defaultResponse, $fieldData, $this->_integrationDetails); + $type = 'course'; + $actionType = 'create_course'; + + break; + case 'mark_lesson_completed': + $response = Hooks::apply(Config::withPrefix('creator_lms_mark_lesson_completed'), $defaultResponse, $fieldData); + $type = 'lesson'; + $actionType = 'mark_lesson_completed'; + + break; + default: + $response = ['success' => false, 'message' => __('Invalid action', 'bit-integrations')]; + $type = 'CreatorLms'; + $actionType = 'unknown'; + + break; + } + + $responseType = isset($response['success']) && $response['success'] ? 'success' : 'error'; + LogHandler::save($this->_integrationID, ['type' => $type, 'type_name' => $actionType], $responseType, $response); + + return $response; + } + + private function generateReqDataFromFieldMap($fieldMap, $fieldValues) + { + $dataFinal = []; + foreach ($fieldMap as $item) { + $triggerValue = $item->formField; + $actionValue = $item->creatorLmsField; + + $dataFinal[$actionValue] = $triggerValue === 'custom' && isset($item->customValue) + ? Common::replaceFieldWithValue($item->customValue, $fieldValues) + : $fieldValues[$triggerValue] ?? ''; + } + + return $dataFinal; + } +} diff --git a/backend/Actions/CreatorLms/Routes.php b/backend/Actions/CreatorLms/Routes.php new file mode 100644 index 00000000..044f1b6d --- /dev/null +++ b/backend/Actions/CreatorLms/Routes.php @@ -0,0 +1,10 @@ +generateReqDataFromFieldMap($fieldValues, $fieldMap); $apiResponse = $this->insertCard($finalData); + $responseType = $apiResponse->id ? 'success' : 'error'; + LogHandler::save($this->_integrationID, ['type' => 'contact', 'type_name' => 'add-contact'], $responseType, $apiResponse); + if ($defaultConf->actions->tags || isset($apiResponse->id)) { $tagResponse = $this->insertTag($apiResponse->id, $defaultConf->selectedTags); - } + $reponseType = HttpHelper::$responseCode === 200 ? 'success' : 'error'; - if (!(isset($apiResponse->id))) { - LogHandler::save($this->_integrationID, ['type' => 'contact', 'type_name' => 'add-contact'], 'error', $apiResponse); - } else { - LogHandler::save($this->_integrationID, ['type' => 'record', 'type_name' => 'add-contact'], 'success', $apiResponse); + LogHandler::save($this->_integrationID, ['type' => 'record', 'type_name' => 'add-tags'], $reponseType, $tagResponse); } return $apiResponse; diff --git a/backend/Core/Util/AllTriggersName.php b/backend/Core/Util/AllTriggersName.php index 1b2623a2..22e15870 100644 --- a/backend/Core/Util/AllTriggersName.php +++ b/backend/Core/Util/AllTriggersName.php @@ -50,6 +50,7 @@ public static function allTriggersName() 'FF' => ['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], + 'CreatorLms' => ['name' => 'Creator LMS', '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], diff --git a/frontend/src/Utils/StaticData/tutorialLinks.js b/frontend/src/Utils/StaticData/tutorialLinks.js index 8c5666cd..ec1c99c4 100644 --- a/frontend/src/Utils/StaticData/tutorialLinks.js +++ b/frontend/src/Utils/StaticData/tutorialLinks.js @@ -558,6 +558,10 @@ const tutorialLinks = { 'https://youtube.com/playlist?list=PL7c6CDwwm-AL0ckxqJPUdiG0syI65HXg2&si=JkJ_0Q0iOA24_wtl', docLink: 'https://bit-integrations.com/wp-docs/actions/academy-lms-integrations-as-an-action/' }, + creatorLms: { + youTubeLink: '', + docLink: 'https://bit-integrations.com/wp-docs/actions/creator-lms-integrations/' + }, woodpecker: { youTubeLink: 'https://youtube.com/playlist?list=PL7c6CDwwm-AL0mmQk0yX6u-HnqDzJeXDu&si=MdiwtkYVb0kBIjPD', diff --git a/frontend/src/Utils/StaticData/webhookIntegrations.js b/frontend/src/Utils/StaticData/webhookIntegrations.js index a846b22f..fb44eaf2 100644 --- a/frontend/src/Utils/StaticData/webhookIntegrations.js +++ b/frontend/src/Utils/StaticData/webhookIntegrations.js @@ -75,6 +75,7 @@ export const customFormIntegrations = [ 'FormGent', 'GeoDirectory', 'StoreEngine', + 'CreatorLms', 'FluentCart', 'MailMint', 'BookingCalendarContactForm', diff --git a/frontend/src/components/AllIntegrations/Autonami/Autonami.jsx b/frontend/src/components/AllIntegrations/Autonami/Autonami.jsx index 47e1f0d5..5aa31e83 100644 --- a/frontend/src/components/AllIntegrations/Autonami/Autonami.jsx +++ b/frontend/src/components/AllIntegrations/Autonami/Autonami.jsx @@ -69,7 +69,7 @@ export default function Autonami({ formFields, setFlow, flow, allIntegURL }) { style={{ width: step === 2 && 900, height: step === 2 && 'auto', - minHeight: step === 2 && `${200}px` + minHeight: step === 2 && `${500}px` }}> { return true } -export const generateMappedField = constantContactConf => { - const requiredFlds = constantContactConf?.default?.constantContactFields.filter( +export const generateMappedField = constantContactFields => { + const requiredFlds = constantContactFields?.filter( fld => fld.required === true ) + return requiredFlds.length > 0 ? requiredFlds.map(field => ({ formField: '', diff --git a/frontend/src/components/AllIntegrations/ConstantContact/ConstantContactFieldMap.jsx b/frontend/src/components/AllIntegrations/ConstantContact/ConstantContactFieldMap.jsx index 0d972ad8..dacb641f 100644 --- a/frontend/src/components/AllIntegrations/ConstantContact/ConstantContactFieldMap.jsx +++ b/frontend/src/components/AllIntegrations/ConstantContact/ConstantContactFieldMap.jsx @@ -1,15 +1,13 @@ import { useRecoilValue } from 'recoil' +import { $appConfigState } from '../../../GlobalStates' import { __, sprintf } from '../../../Utils/i18nwrap' -import MtInput from '../../Utilities/MtInput' +import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' +import TagifyInput from '../../Utilities/TagifyInput' import { addFieldMap, delFieldMap, handleFieldMapping } from '../IntegrationHelpers/ConstantContactIntegrationHelpers' -import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' -import { $appConfigState } from '../../../GlobalStates' -import { generateMappedField } from './ConstantContactCommonFunc' -import TagifyInput from '../../Utilities/TagifyInput' import { handleCustomValue } from '../IntegrationHelpers/IntegrationHelpers' export default function ConstantContactFieldMap({ @@ -19,17 +17,11 @@ export default function ConstantContactFieldMap({ constantContactConf, setConstantContactConf }) { - if (constantContactConf?.field_map?.length === 1 && field.constantContactFormField === '') { - const newConf = { ...constantContactConf } - const tmp = generateMappedField(newConf) - newConf.field_map = tmp - setConstantContactConf(newConf) - } - const requiredFlds = constantContactConf?.default?.constantContactFields.filter(fld => fld.required === true) || [] const nonRequiredFlds = constantContactConf?.default?.constantContactFields.filter(fld => fld.required === false) || [] + const btcbi = useRecoilValue($appConfigState) const { isPro } = btcbi diff --git a/frontend/src/components/AllIntegrations/CreatorLms/CreatorLms.jsx b/frontend/src/components/AllIntegrations/CreatorLms/CreatorLms.jsx new file mode 100644 index 00000000..b8e93083 --- /dev/null +++ b/frontend/src/components/AllIntegrations/CreatorLms/CreatorLms.jsx @@ -0,0 +1,106 @@ +import { useState } from 'react' +import 'react-multiple-select-dropdown-lite/dist/index.css' +import { useNavigate, useParams } from 'react-router-dom' +import BackIcn from '../../../Icons/BackIcn' +import { __ } from '../../../Utils/i18nwrap' +import SnackMsg from '../../Utilities/SnackMsg' +import { saveIntegConfig } from '../IntegrationHelpers/IntegrationHelpers' +import IntegrationStepThree from '../IntegrationHelpers/IntegrationStepThree' +import CreatorLmsAuthorization from './CreatorLmsAuthorization' +import { checkMappedFields } from './CreatorLmsCommonFunc' +import CreatorLmsIntegLayout from './CreatorLmsIntegLayout' + +export default function CreatorLms({ formFields, setFlow, flow, allIntegURL }) { + const navigate = useNavigate() + const { formID } = useParams() + const [isLoading, setIsLoading] = useState(false) + const [step, setStep] = useState(1) + const [snack, setSnackbar] = useState({ show: false }) + const [creatorLmsConf, setCreatorLmsConf] = useState({ + name: 'Creator LMS', + type: 'CreatorLms', + field_map: [{ formField: '', creatorLmsField: '' }], + actions: {}, + mainAction: '' + }) + + const nextPage = val => { + setTimeout(() => { + document.getElementById('btcd-settings-wrp').scrollTop = 0 + }, 300) + + if (val === 3) { + if (!checkMappedFields(creatorLmsConf)) { + setSnackbar({ + show: true, + msg: __('Please map all required fields to continue.', 'bit-integrations') + }) + return + } + + if (creatorLmsConf.name !== '' && creatorLmsConf.field_map.length > 0) { + setStep(val) + } + } else { + setStep(val) + } + } + + return ( +
+ +
{/* */}
+ + {/* STEP 1 */} + + + {/* STEP 2 */} +
+ +
+
+
+ +
+ + {/* STEP 3 */} + + saveIntegConfig(flow, setFlow, allIntegURL, creatorLmsConf, navigate, '', '', setIsLoading) + } + isLoading={isLoading} + /> +
+ ) +} diff --git a/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsAuthorization.jsx b/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsAuthorization.jsx new file mode 100644 index 00000000..f39404b7 --- /dev/null +++ b/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsAuthorization.jsx @@ -0,0 +1,120 @@ +import { useState } from 'react' +import BackIcn from '../../../Icons/BackIcn' +import bitsFetch from '../../../Utils/bitsFetch' +import { __ } from '../../../Utils/i18nwrap' +import tutorialLinks from '../../../Utils/StaticData/tutorialLinks' +import LoaderSm from '../../Loaders/LoaderSm' +import TutorialLink from '../../Utilities/TutorialLink' + +export default function CreatorLmsAuthorization({ + formID, + creatorLmsConf, + setCreatorLmsConf, + step, + nextPage, + isLoading, + setIsLoading, + setSnackbar, + isInfo +}) { + const [isAuthorized, setIsAuthorized] = useState(false) + const [showAuthMsg, setShowAuthMsg] = useState(false) + const { creatorLms } = tutorialLinks + + const authorizeHandler = () => { + setIsLoading('auth') + bitsFetch({}, 'creator_lms_authorize').then(result => { + if (result?.success) { + setIsAuthorized(true) + setSnackbar({ + show: true, + msg: __('Connected with Creator LMS Successfully', 'bit-integrations') + }) + } + setIsLoading(false) + setShowAuthMsg(true) + }) + } + + const handleInput = e => { + const newConf = { ...creatorLmsConf } + newConf[e.target.name] = e.target.value + setCreatorLmsConf(newConf) + } + + return ( +
+ {creatorLms?.youTubeLink && ( + + )} + {creatorLms?.docLink && } + +
+ {__('Integration Name:', 'bit-integrations')} +
+ + + {isLoading === 'auth' && ( +
+ + {__('Checking if Creator LMS is authorized!!!', 'bit-integrations')} +
+ )} + + {showAuthMsg && !isAuthorized && !isLoading && ( +
+
+
+ +
+
+ {__('Creator LMS is not activated or not installed', 'bit-integrations')} +
+
+
+ )} + + {showAuthMsg && isAuthorized && !isLoading && ( +
+
+ +
+
{__('Creator LMS is activated', 'bit-integrations')}
+
+ )} + + +
+ +
+ ) +} diff --git a/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsCommonFunc.js b/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsCommonFunc.js new file mode 100644 index 00000000..f5e59316 --- /dev/null +++ b/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsCommonFunc.js @@ -0,0 +1,35 @@ +import { create } from 'mutative' + +export const handleInput = (e, creatorLmsConf, setCreatorLmsConf) => { + const { name, value } = e.target + setCreatorLmsConf(prevConf => + create(prevConf, draftConf => { + draftConf[name] = value + }) + ) +} + +export const checkMappedFields = creatorLmsConf => { + const mappedFields = creatorLmsConf?.field_map + ? creatorLmsConf.field_map.filter( + mappedField => + !mappedField.formField || + !mappedField.creatorLmsField || + (mappedField.formField === 'custom' && !mappedField.customValue) + ) + : [] + if (mappedFields.length > 0) { + return false + } + return true +} + +export const generateMappedField = fields => { + const requiredFlds = fields.filter(fld => fld.required === true) + return requiredFlds.length > 0 + ? requiredFlds.map(field => ({ + formField: '', + creatorLmsField: field.key + })) + : [{ formField: '', creatorLmsField: '' }] +} diff --git a/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsFieldMap.jsx b/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsFieldMap.jsx new file mode 100644 index 00000000..0c2e081b --- /dev/null +++ b/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsFieldMap.jsx @@ -0,0 +1,113 @@ +import { useRecoilValue } from 'recoil' +import { $appConfigState } from '../../../GlobalStates' +import { __, sprintf } from '../../../Utils/i18nwrap' +import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' +import TagifyInput from '../../Utilities/TagifyInput' +import { + addFieldMap, + delFieldMap, + handleCustomValue, + handleFieldMapping +} from '../GlobalIntegrationHelper' + +export default function CreatorLmsFieldMap({ + i, + formFields, + field, + creatorLmsConf, + setCreatorLmsConf +}) { + const btcbi = useRecoilValue($appConfigState) + const { isPro } = btcbi + + const requiredFlds = creatorLmsConf?.creatorLmsFields?.filter(fld => fld.required === true) || [] + const nonRequiredFlds = + creatorLmsConf?.creatorLmsFields?.filter(fld => fld.required === false) || [] + + return ( +
+
+
+ + + {field.formField === 'custom' && ( + handleCustomValue(e, i, creatorLmsConf, setCreatorLmsConf)} + label={__('Custom Value', 'bit-integrations')} + className="mr-2" + type="text" + value={field.customValue} + placeholder={__('Custom Value', 'bit-integrations')} + formFields={formFields} + /> + )} + + +
+ {i >= requiredFlds.length && ( + <> + + + + )} +
+
+ ) +} diff --git a/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsIntegLayout.jsx b/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsIntegLayout.jsx new file mode 100644 index 00000000..68296fd6 --- /dev/null +++ b/frontend/src/components/AllIntegrations/CreatorLms/CreatorLmsIntegLayout.jsx @@ -0,0 +1,160 @@ +import { create } from 'mutative' +import MultiSelect from 'react-multiple-select-dropdown-lite' +import { useRecoilValue } from 'recoil' +import { $appConfigState } from '../../../GlobalStates' +import { __ } from '../../../Utils/i18nwrap' +import Loader from '../../Loaders/Loader' +import { checkIsPro, getProLabel } from '../../Utilities/ProUtilHelpers' +import { addFieldMap } from '../IntegrationHelpers/IntegrationHelpers' +import { + generateMappedField +} from './CreatorLmsCommonFunc' +import CreatorLmsFieldMap from './CreatorLmsFieldMap' +import { + courseStatusOptions, + CreateCourseFields, + CreateStudentFields, + EnrollUserInCourseFields, + MarkLessonCompletedFields, + modules, + UpdateStudentFields +} from './staticData' + +export default function CreatorLmsIntegLayout({ + formID, + formFields, + creatorLmsConf, + setCreatorLmsConf, + isLoading, + setIsLoading, + setSnackbar +}) { + const appConfig = useRecoilValue($appConfigState) + const { isPro } = appConfig + + const handleMainAction = value => { + setCreatorLmsConf(prevConf => + create(prevConf, draftConf => { + draftConf.mainAction = value + draftConf.courseStatus = null + + switch (value) { + case 'create_student': + draftConf.creatorLmsFields = CreateStudentFields + break + case 'update_student_data': + draftConf.creatorLmsFields = UpdateStudentFields + break + case 'enroll_user_in_course': + draftConf.creatorLmsFields = EnrollUserInCourseFields + break + case 'create_course': + draftConf.creatorLmsFields = CreateCourseFields + break + case 'mark_lesson_completed': + draftConf.creatorLmsFields = MarkLessonCompletedFields + break + default: + draftConf.creatorLmsFields = [] + } + + draftConf.field_map = generateMappedField(draftConf.creatorLmsFields) + }) + ) + } + + return ( + <> +
+
+ {__('Action:', 'bit-integrations')} + handleMainAction(value)} + options={modules?.map(action => ({ + label: checkIsPro(isPro, action.is_pro) ? action.label : getProLabel(action.label), + value: action.name, + disabled: !checkIsPro(isPro, action.is_pro) + }))} + singleSelect + closeOnSelect + /> +
+ + {creatorLmsConf?.mainAction === 'create_course' && ( + <> +
+
+ {__('Course Status:', 'bit-integrations')} + + setCreatorLmsConf(prevConf => + create(prevConf, draftConf => { + draftConf.courseStatus = val + }) + ) + } + singleSelect + closeOnSelect + /> +
+ + )} + + {isLoading && ( + + )} + + {creatorLmsConf?.mainAction && creatorLmsConf.creatorLmsFields && creatorLmsConf.creatorLmsFields.length > 0 && ( +
+ {__('Map Fields', 'bit-integrations')} +
+
+
+ {__('Form Fields', 'bit-integrations')} +
+
+ {__('Creator LMS Fields', 'bit-integrations')} +
+
+ + {creatorLmsConf?.field_map?.map((itm, i) => ( + + ))} +
+ +
+
+
+ )} + + ) +} diff --git a/frontend/src/components/AllIntegrations/CreatorLms/EditCreatorLms.jsx b/frontend/src/components/AllIntegrations/CreatorLms/EditCreatorLms.jsx new file mode 100644 index 00000000..259c9b77 --- /dev/null +++ b/frontend/src/components/AllIntegrations/CreatorLms/EditCreatorLms.jsx @@ -0,0 +1,76 @@ +import { useState } from 'react' +import { useNavigate, useParams } from 'react-router-dom' +import { useRecoilState, useRecoilValue } from 'recoil' +import { $actionConf, $formFields, $newFlow } from '../../../GlobalStates' +import { __ } from '../../../Utils/i18nwrap' +import SnackMsg from '../../Utilities/SnackMsg' +import { saveActionConf } from '../IntegrationHelpers/IntegrationHelpers' +import IntegrationStepThree from '../IntegrationHelpers/IntegrationStepThree' +import SetEditIntegComponents from '../IntegrationHelpers/SetEditIntegComponents' +import { checkMappedFields, handleInput } from './CreatorLmsCommonFunc' +import CreatorLmsIntegLayout from './CreatorLmsIntegLayout' + +export default function EditCreatorLms({ allIntegURL }) { + const navigate = useNavigate() + const { id, formID } = useParams() + + const [creatorLmsConf, setCreatorLmsConf] = useRecoilState($actionConf) + const [flow, setFlow] = useRecoilState($newFlow) + const formFields = useRecoilValue($formFields) + const [isLoading, setIsLoading] = useState(false) + const [snack, setSnackbar] = useState({ show: false }) + + return ( +
+ + +
+ {__('Integration Name:', 'bit-integrations')} + handleInput(e, creatorLmsConf, setCreatorLmsConf)} + name="name" + value={creatorLmsConf.name} + type="text" + placeholder={__('Integration Name...', 'bit-integrations')} + /> +
+
+ + + + + + + saveActionConf({ + flow, + setFlow, + allIntegURL, + conf: creatorLmsConf, + navigate, + id, + edit: 1, + setIsLoading, + setSnackbar + }) + } + disabled={!checkMappedFields(creatorLmsConf)} + isLoading={isLoading} + dataConf={creatorLmsConf} + setDataConf={setCreatorLmsConf} + formFields={formFields} + /> +
+
+ ) +} diff --git a/frontend/src/components/AllIntegrations/CreatorLms/staticData.js b/frontend/src/components/AllIntegrations/CreatorLms/staticData.js new file mode 100644 index 00000000..db9fa1fd --- /dev/null +++ b/frontend/src/components/AllIntegrations/CreatorLms/staticData.js @@ -0,0 +1,47 @@ +import { __ } from '../../../Utils/i18nwrap' + +export const modules = [ + { name: 'create_student', label: __('Create Student', 'bit-integrations'), is_pro: true }, + { name: 'update_student_data', label: __('Update Student Data', 'bit-integrations'), is_pro: true }, + { name: 'enroll_user_in_course', label: __('Enroll User in Course', 'bit-integrations'), is_pro: true }, + { name: 'create_course', label: __('Create Course', 'bit-integrations'), is_pro: true }, + { name: 'mark_lesson_completed', label: __('Mark Lesson Completed', 'bit-integrations'), is_pro: true } +] + +export const CreateStudentFields = [ + { key: 'user_email', label: __('Student Email', 'bit-integrations'), required: true }, + { key: 'username', label: __('Username', 'bit-integrations'), required: false }, + { key: 'password', label: __('Password', 'bit-integrations'), required: false }, + { key: 'first_name', label: __('First Name', 'bit-integrations'), required: false }, + { key: 'last_name', label: __('Last Name', 'bit-integrations'), required: false } +] + +export const UpdateStudentFields = [ + { key: 'user_email', label: __('Student Email', 'bit-integrations'), required: true }, + { key: 'new_email', label: __('New Email Address', 'bit-integrations'), required: false }, + { key: 'first_name', label: __('First Name', 'bit-integrations'), required: false }, + { key: 'last_name', label: __('Last Name', 'bit-integrations'), required: false }, + { key: 'display_name', label: __('Display Name', 'bit-integrations'), required: false } +] + +export const EnrollUserInCourseFields = [ + { key: 'user_email', label: __('Student Email', 'bit-integrations'), required: true }, + { key: 'course_id', label: __('Course ID', 'bit-integrations'), required: true } +] + +export const CreateCourseFields = [ + { key: 'course_title', label: __('Course Title', 'bit-integrations'), required: true }, + { key: 'course_description', label: __('Course Description', 'bit-integrations'), required: true } +] + +export const courseStatusOptions = [ + { label: __('Draft', 'bit-integrations'), value: 'draft' }, + { label: __('Publish', 'bit-integrations'), value: 'publish' }, + { label: __('Pending', 'bit-integrations'), value: 'pending' } +] + +export const MarkLessonCompletedFields = [ + { key: 'user_email', label: __('Student Email', 'bit-integrations'), required: true }, + { key: 'course_id', label: __('Course ID', 'bit-integrations'), required: true }, + { key: 'lesson_id', label: __('Lesson ID', 'bit-integrations'), required: true } +] diff --git a/frontend/src/components/AllIntegrations/EditInteg.jsx b/frontend/src/components/AllIntegrations/EditInteg.jsx index 9f03f770..9d086885 100644 --- a/frontend/src/components/AllIntegrations/EditInteg.jsx +++ b/frontend/src/components/AllIntegrations/EditInteg.jsx @@ -169,6 +169,7 @@ const EditBento = lazy(() => import('./Bento/EditBento')) const EditLine = lazy(() => import('./Line/EditLine')) const EditACPT = lazy(() => import('./ACPT/EditACPT')) const EditWishlistMember = lazy(() => import('./WishlistMember/EditWishlistMember')) +const EditCreatorLms = lazy(() => import('./CreatorLms/EditCreatorLms')) const EditFluentCart = lazy(() => import('./FluentCart/EditFluentCart')) const EditWPCafe = lazy(() => import('./WPCafe/EditWPCafe')) const EditNotificationX = lazy(() => import('./NotificationX/EditNotificationX')) @@ -581,6 +582,8 @@ const IntegType = memo(({ allIntegURL, flow }) => { return case 'Wishlist Member': return + case 'CreatorLms': + return case 'FluentCart': return case 'WPCafe': diff --git a/frontend/src/components/AllIntegrations/FluentCRM/FluentCrm.jsx b/frontend/src/components/AllIntegrations/FluentCRM/FluentCrm.jsx index 30a79025..760cd830 100644 --- a/frontend/src/components/AllIntegrations/FluentCRM/FluentCrm.jsx +++ b/frontend/src/components/AllIntegrations/FluentCRM/FluentCrm.jsx @@ -78,7 +78,7 @@ export default function FluentCrm({ formFields, setFlow, flow, allIntegURL }) { style={{ width: step === 2 && 900, height: step === 2 && 'auto', - minHeight: step === 2 && `${200}px` + minHeight: step === 2 && `${500}px` }}> import('./Bento/BentoAuthorization')) const LineAuthorization = lazy(() => import('./Line/LineAuthorization')) const ACPTAuthorization = lazy(() => import('./ACPT/ACPTAuthorization')) const WishlistMemberAuthorization = lazy(() => import('./WishlistMember/WishlistMemberAuthorization')) +const CreatorLmsAuthorization = lazy(() => import('./CreatorLms/CreatorLmsAuthorization')) const FluentCartAuthorization = lazy(() => import('./FluentCart/FluentCartAuthorization')) const WPCafeAuthorization = lazy(() => import('./WPCafe/WPCafeAuthorization')) const TeamsForWooCommerceMembershipsAuthorization = lazy( @@ -616,6 +617,8 @@ export default function IntegInfo() { return case 'WishlistMember': return + case 'CreatorLms': + return case 'FluentCart': return case 'WPCafe': diff --git a/frontend/src/components/AllIntegrations/Keap/KeapCommonFunc.js b/frontend/src/components/AllIntegrations/Keap/KeapCommonFunc.js index 4923a7fc..9de202b1 100644 --- a/frontend/src/components/AllIntegrations/Keap/KeapCommonFunc.js +++ b/frontend/src/components/AllIntegrations/Keap/KeapCommonFunc.js @@ -181,8 +181,8 @@ export const refreshCustomFields = (id, confTmp, setConf, setIsLoading, setSnack const newConf = { ...confTmp } if (result.data) { newConf.customFields = result.data - newConf.field_map = generateMappedField(newConf) } + newConf.field_map = generateMappedField(newConf) setConf(newConf) setIsLoading(false) diff --git a/frontend/src/components/AllIntegrations/Keap/KeapFieldMap.jsx b/frontend/src/components/AllIntegrations/Keap/KeapFieldMap.jsx index 5d1f3e70..5ab71824 100644 --- a/frontend/src/components/AllIntegrations/Keap/KeapFieldMap.jsx +++ b/frontend/src/components/AllIntegrations/Keap/KeapFieldMap.jsx @@ -1,21 +1,12 @@ import { useRecoilValue } from 'recoil' +import { $appConfigState } from '../../../GlobalStates' import { __, sprintf } from '../../../Utils/i18nwrap' -import MtInput from '../../Utilities/MtInput' -import { addFieldMap, delFieldMap, handleFieldMapping } from './KeapIntegrationHelpers' import { SmartTagField } from '../../../Utils/StaticData/SmartTagField' -import { $appConfigState } from '../../../GlobalStates' -import { generateMappedField } from './KeapCommonFunc' import TagifyInput from '../../Utilities/TagifyInput' import { handleCustomValue } from '../IntegrationHelpers/IntegrationHelpers' +import { addFieldMap, delFieldMap, handleFieldMapping } from './KeapIntegrationHelpers' export default function KeapFieldMap({ i, formFields, field, keapConf, setKeapConf }) { - if (keapConf?.field_map?.length === 1 && field.keapField === '') { - const newConf = { ...keapConf } - const tmp = generateMappedField(newConf) - newConf.field_map = tmp - setKeapConf(newConf) - } - const allFields = keapConf?.customFields ? [...keapConf?.contactFields, ...keapConf?.customFields] : keapConf?.contactFields diff --git a/frontend/src/components/AllIntegrations/MailPoet/MailPoet.jsx b/frontend/src/components/AllIntegrations/MailPoet/MailPoet.jsx index 3e878364..fb2ee91e 100644 --- a/frontend/src/components/AllIntegrations/MailPoet/MailPoet.jsx +++ b/frontend/src/components/AllIntegrations/MailPoet/MailPoet.jsx @@ -69,7 +69,7 @@ export default function MailPoet({ formFields, setFlow, flow, allIntegURL }) { style={{ width: step === 2 && 900, height: step === 2 && 'auto', - minHeight: step === 2 && `${200}px` + minHeight: step === 2 && `${500}px` }}> import('./Bento/Bento')) const Line = lazy(() => import('./Line/Line')) const ACPT = lazy(() => import('./ACPT/ACPT')) const WishlistMember = lazy(() => import('./WishlistMember/WishlistMember')) +const CreatorLms = lazy(() => import('./CreatorLms/CreatorLms')) const FluentCart = lazy(() => import('./FluentCart/FluentCart')) const WPCafe = lazy(() => import('./WPCafe/WPCafe')) const NotificationX = lazy(() => import('./NotificationX/NotificationX')) @@ -1635,6 +1636,15 @@ export default function NewInteg({ allIntegURL }) { setFlow={setFlow} /> ) + case 'CreatorLms': + return ( + + ) case 'FluentCart': return (