I created a registration form custom component for my builder.io page and it seems to work in production. My builder.io page with the component looks like this…
This is exactly what I want! The problem is when I open it for editing, it looks like this…
It is pretty clear that the react-bootstrap components are not being defined. The registration grid is made using the Col, Row elements from react-bootstrap. Here is the code for the custom component…
"use client";
import React, { Dispatch, useEffect } from "react";
// hooks forms
import { CompactFormRegister, CompactSignupSchema } from "./CompactRegistrationSchema";
import { useFieldArray, useForm, useWatch } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import {
BrokerageInfoSchema,
FormBrokerageInfo,
} from "./BrokerageInfoSchema";
// redux
import { RootState } from "../../redux/store";
import { useDispatch, useSelector } from "react-redux";
import { register } from "../../redux/auth/auth.actions";
// services
import BrokerageService from "../../api/brokerage.service";
// modals
import { UserProfileModel } from "../../shared/model/UserProfile";
import { BrokerageModel } from "../../shared/model/Brokerage";
import { MarketModel } from "../../shared/model/Market";
// const
import { acceptTerms, refByOptions } from "../../constants/Consts";
// utils
import { transformNameAndIdToOption } from "../../utils/DropdownOptions";
import { formatPhoneNumber } from "../../utils/Validations";
import { toTitleCase } from "../../utils/TitleCase";
// ui
import CustomButton from "../../components/Button/CustomButton";
import { FormInputText } from "../../components/FormComponents/FormInputText";
import { FormInputCheckbox } from "../../components/FormComponents/FormInputCheckbox";
import { FormInputDropdown } from "../../components/FormComponents/FormInputDropdown";
import { FormInputAsyncSelect } from "../../components/FormComponents/FormInputAsyncSelect";
import { Col, Container, Form, Modal, Row } from "react-bootstrap";
import { CustomModal } from "../../components/Modal/CustomModal";
import ImageUpload from "../../components/ImageUpload/ImageUpload";
import { Avatar } from "@mui/material";
import { toast } from "react-toastify";
// icons
import { ChevronBarDown, Eye, EyeSlash } from "react-bootstrap-icons";
import { Variables_E } from "../../enums/rl-variables";
import { set, String } from "lodash";
import ToastSpinner from "../../components/ToastSpinner/ToastSpinner";
import { invImageURL } from "../../utils/TextFormat";
import { StoreProvider } from "@/app/StoreProvider";
interface CompactRegistrationFormProps {
affiliateId?: number;
affiliateName?: string;
}
const CompactRegistrationForm: React.FunctionComponent<CompactRegistrationFormProps> = (
{
affiliateId,
affiliateName,
}
) => {
const enableUploadLogo = false; // Disabled since it doesn't work. Assumes customer record already exists.
const enableUploadHeadShot = false; // Disabled since it doesn't work. Assumes customer record already exists.
// const dispatch: Dispatch<any> = useDispatch();
// const marketList: MarketModel[] = useSelector(
// (state: RootState) => state.market.marketList
// );
// hook-forms
const methods = useForm<CompactFormRegister>({
// resolver: yupResolver(CompactSignupSchema()),
});
const { handleSubmit, control, setValue, watch ,getValues} = methods;
const methodsBrokerage = useForm<FormBrokerageInfo>({
// resolver: yupResolver(BrokerageInfoSchema),
});
const {
handleSubmit: brokerageHandleSubmit,
control: brokerageControl,
setValue: setValueBrokerage,
} = methodsBrokerage;
// watch-fields
const watchFieldArray = watch("test");
const phoneNumberWatch = useWatch({
control,
name: "phone",
});
React.useEffect(() => {
if (phoneNumberWatch && phoneNumberWatch.length > 0) {
let FPN = formatPhoneNumber(phoneNumberWatch);
setValue("phone", FPN);
}
}, [phoneNumberWatch]);
// useStates
const [password, setPassword] = React.useState("password");
const [passwordConfirm, setPasswordConfirm] = React.useState("password");
const [selectedIndex, setSelectedIndex] = React.useState();
const [marketOptions, setMarketOptions] = React.useState<any>([]);
const [showReferalSource, setShowReferalSource] = React.useState<boolean>(false);
//brokerage other option toggle modal
const [showModalOtherBrokerage, setShowModalOtherBrokerage] =
React.useState(false);
const toggleModalOtherBrokerage = () => {
setShowModalOtherBrokerage((v) => !v);
};
// upload logo
const [showUploadHeadShotModal, setShowUploadHeadShotModal] =
React.useState(false);
const toggleModalUploadHeadShot = React.useCallback(() => {
setShowUploadHeadShotModal((v) => !v);
}, []);
// upload logo
const [showUploadLogoModal, setShowUploadLogoModal] = React.useState(false);
const [marketId, setMarketId] = React.useState<string>("");
const [brokerage, setBrokerage] = React.useState<any>(null);
const toggleModalUploadLogo = React.useCallback(() => {
setShowUploadLogoModal((v) => !v);
}, []);
// market dropdown
// React.useEffect(() => {
// if (marketList) {
// const marketOptionsDropDown = transformNameAndIdToOption(marketList);
// setMarketOptions(marketOptionsDropDown);
// }
// }, [marketList]);
const handleMarketChange = async (e: any) => {
setMarketId(e.target.value);
};
const handleBrokerChange = async (
e: any
) => {
if(e.label === "Add New") {
toggleModalOtherBrokerage();
} else {
setBrokerage(e);
}
}
const togglePassword = () => {
setPassword(password === "password" ? "text" : "password");
};
const toggleConfirmPassword = () => {
setPasswordConfirm(passwordConfirm === "password" ? "text" : "password");
};
// submit other brokerage
const addBroker = (data: BrokerageModel) => {
return BrokerageService.addBrokerage(data).then(
async (response: any) => {
toast.success(toTitleCase("new brokerage added"));
setBrokerage({
value: response.data.data.id,
label: response.data.data.name + " " + response.data.data.email,
})
toggleModalOtherBrokerage();
},
(error: any) => {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
toast.warning(message, { autoClose: false });
}
);
};
const onSubmitBrokerage = (data: BrokerageModel) => {
toast.dismiss();
data.market_id = marketId;
addBroker(data);
};
const referral_from = useWatch({ control, name: 'referral_from' });
useEffect(()=>{
!getValues('referral_from') && setShowReferalSource(false)
},[referral_from])
const onSubmit = async (data: CompactFormRegister) => {
toast.dismiss();
let brokerageArray = [ brokerage.value ];
let marketArray = [ marketId ];
let RegData: UserProfileModel = {
first_name: data.first_name,
email: data.username,
last_name: data.last_name,
username: data.username,
phone: data.phone,
referral_from: 'affiliate',
referral_source_name: affiliateName,
referral_source_id: affiliateId,
password_hash: data.password_hash,
brokerage: brokerageArray,
markets: marketArray,
email_type: "primary",
email_intent: "",
};
let regMessage;
try {
const loadingToastId = toast(
<ToastSpinner message="Processing..." type="loading" />,
{
closeButton: false,
autoClose: false,
}
);
// regMessage = await dispatch(register(RegData));
regMessage = "success"; // Simulating successful registration for testing purposes
toast.dismiss(loadingToastId);
if (regMessage === "success") {
toast.success(
<ToastSpinner message="Registration successful" type="success" />
);
// navigate(`/`);
} else {
toast.error(
<ToastSpinner
message="Registration failed. Please try again."
type="error"
/>
, { autoClose: false }
);
}
} catch (error) {
console.error(error);
toast.error(
<ToastSpinner
message="An error occurred. Please try again later."
type="error"
/>
, { autoClose: false }
);
}
};
const handleCancel = () => {
toggleModalOtherBrokerage();
};
return (
<>
<StoreProvider>
<Form
onSubmit={handleSubmit(onSubmit)}
className="form"
autoComplete="off"
>
<Container className="">
<Row className="d-flex justify-content-center mb-3">
<Col md={4} xs={12} className="form-group">
<FormInputText
name="first_name"
control={control}
label="First Name"
/>
</Col>
<Col md={4} xs={12} className="form-group">
<FormInputText
name="last_name"
control={control}
label="Last Name"
/>
</Col>
</Row>
<Row className="d-flex justify-content-center mb-3">
<Col md={4} xs={12} className="form-group">
<FormInputText name="username" control={control} label="Email" />
</Col>
<Col xs={12} md={4} className="form-group">
<FormInputText name="phone" control={control} label="Mobile" />
</Col>
</Row>
<Row className="d-flex justify-content-center mb-3">
<Col
xs={12}
md={4}
className="form-group rl-dropdown-content rl-dropdown-multilist rl-select-noinput"
>
<FormInputDropdown
placeholder="Assign Market"
name="market"
control={control}
label="Select Market"
options={marketOptions}
setValue={setValue}
customOnChange={(e) => handleMarketChange(e)}
defaultValue=""
showEndAdornment={false}
/>
</Col>
<Col
xs={12}
md={4}
className="form-group rl-dropdown-content rl-dropdown-option rl-dropdown-custom select-agent rl-dropdown-select rl-brokerage-input"
>
<FormInputAsyncSelect
placeholder="Select Brokerage"
name="brokerage"
customOnChange={(e) =>
handleBrokerChange(e)
}
control={control}
filter={{
marketId: marketId,
}}
type="withBrokerageOther"
label="Brokerage - Choose other if not listed"
disabled={marketId ? false : true}
showEndAdornment={false}
/>
</Col>
</Row>
<Row className="d-flex justify-content-center mb-3">
<Col xs={12} md={4} className="form-group">
<FormInputText
name="password_hash"
control={control}
label="Password"
type={password === "password" ? "password" : "text"}
endAdornment={
<span onClick={togglePassword} className="show-hide-icon">
{password === "password" ? <EyeSlash /> : <Eye />}
</span>
}
/>
</Col>
<Col xs={12} md={4} className="form-group">
<FormInputText
name="confirmPassword"
control={control}
label="Re-type Password"
type={passwordConfirm === "password" ? "password" : "text"}
endAdornment={
<span
onClick={toggleConfirmPassword}
className="show-hide-icon"
>
{passwordConfirm === "password" ? <EyeSlash /> : <Eye />}
</span>
}
/>
</Col>
</Row>
<div className="flex_center mb-3">
<div className="form-group no-asterisk rl_radio_form">
<FormInputCheckbox
name="acceptTerms"
control={control}
options={acceptTerms}
setValue={setValue}
label={
<>
I agree to{" "}
<a
href="https://rocketlisterwp.azurewebsites.net/terms-and-conditions"
target="_blank"
rel="noopener noreferrer"
>
Terms and Services
</a>
</>
}
/>
</div>
</div>
<CustomButton
type="submit"
className="btn btn-primary mb-3 rl-btn-primary"
>
Register
</CustomButton>
</Container>
</Form>
</StoreProvider>
{/* Modal when other is chosen for brokerage */}
<CustomModal
showConfirmCallToAction={true}
show={showModalOtherBrokerage}
close={toggleModalOtherBrokerage}
footer={false}
header={true}
headerTitle="Add New Brokerage"
size="sm"
className="rl-custom-modal"
>
<Modal.Body className="reset-password ">
<Form
onSubmit={brokerageHandleSubmit(onSubmitBrokerage)}
className="form mb-4"
>
<Row className="mb-3">
<Col className="form-group text-start">
<FormInputText
name="name"
control={brokerageControl}
label="Brokerage"
/>
</Col>
</Row>
<Row className="mt-4 rl-modal-btn">
<Col md={12} className="rl-button-group ">
<CustomButton type="submit" className="rl-btn-primary mx-2">
Save
</CustomButton>
<CustomButton
className="rl-btn-secondary"
onClick={() => handleCancel()}
>
Cancel
</CustomButton>
</Col>
</Row>
</Form>
</Modal.Body>
</CustomModal>
</>
);
};
export default CompactRegistrationForm;
To be clear, the first screenshot is the actual page that I created with the visual editor by dropping the registration component into it. So the custom component is actually working. It simply looks wrong in the visual editor. How do I fix this?


