fixed reg trunk validation cannot move tab and focus to missing fields (#574)

* fixed reg trunk validation cannot move tab and focus to missing fields

* fixed reg trunk validation cannot move tab and focus to missing fields

* wip
This commit is contained in:
Hoan Luu Huu
2025-10-27 18:21:39 +07:00
committed by GitHub
parent 19742ab67e
commit e6c5a18c87

View File

@@ -906,26 +906,33 @@ export const CarrierForm = ({
const invalidField = e.target as unknown as HTMLInputElement;
const fieldName = invalidField.name || invalidField.id;
// Map field names to tabs
if (fieldName === "carrier_name") {
setActiveTab("general");
} else if (fieldName?.includes("inbound_auth_")) {
setActiveTab("inbound");
} else if (
fieldName?.includes("sip_username") ||
fieldName?.includes("sip_password") ||
fieldName?.includes("sip_realm") ||
fieldName?.includes("from_user") ||
fieldName?.includes("from_domain")
) {
setActiveTab("outbound"); // Changed from "registration" to "outbound"
} else if (fieldName?.includes("sip_")) {
setActiveTab("sip");
// Simple mapping: which tab should this field be on?
let targetTab = "general";
if (fieldName?.includes("inbound_auth_")) {
targetTab = "inbound";
} else if (fieldName?.includes("sip_") || fieldName?.includes("from_")) {
targetTab = "outbound";
} else if (fieldName?.includes("smpp_")) {
setActiveTab("smpp");
targetTab = "smpp";
}
// Allow the default browser validation message to show
// If we're not on the right tab, switch to it
if (activeTab !== targetTab) {
e.preventDefault(); // Stop the "not focusable" error
setActiveTab(targetTab);
setTimeout(() => {
const field =
document.getElementById(fieldName) ||
document.querySelector(`[name="${fieldName}"]`);
if (field && field instanceof HTMLInputElement) {
field.focus();
field.scrollIntoView({ behavior: "smooth", block: "center" });
field.reportValidity();
}
}, 100);
}
};
return (
@@ -1401,122 +1408,164 @@ export const CarrierForm = ({
</MXS>
</fieldset>
<fieldset>
<Checkzone
hidden
name="sip_credentials"
label="Authentication"
initialCheck={initialRegister}
handleChecked={(e) => {
if (!e.target.checked) {
setSipUser("");
setSipPass("");
setSipRegister(false);
}
}}
>
<MS>Does your carrier require authentication?</MS>
<label htmlFor="sip_username">
Auth username{" "}
{sipPass || sipRegister || trunkType === "reg" ? (
<span>*</span>
) : (
""
)}
</label>
<input
id="sip_username"
name="sip_username"
type="text"
value={sipUser}
placeholder="SIP username for authenticating outbound calls"
required={
sipRegister || sipPass.length > 0 || trunkType === "reg"
}
onChange={(e) => {
setSipUser(e.target.value);
}}
/>
<label htmlFor="sip_password">
Password
{sipUser || sipRegister || trunkType === "reg" ? (
<span>*</span>
) : (
""
)}
</label>
<Passwd
id="sip_password"
name="sip_password"
value={sipPass}
placeholder="SIP password for authenticating outbound calls"
required={
sipRegister || sipUser.length > 0 || trunkType === "reg"
}
onChange={(e) => {
setSipPass(e.target.value);
}}
/>
</Checkzone>
{/* Authentication Fields - shared component */}
{(() => {
const authFields = (
<>
<label htmlFor="sip_username">
Auth username{" "}
{(sipPass || sipRegister || trunkType === "reg") && (
<span>*</span>
)}
</label>
<input
id="sip_username"
name="sip_username"
type="text"
value={sipUser}
placeholder="SIP username for authenticating outbound calls"
required={
trunkType === "reg" || sipRegister || sipPass.length > 0
}
onChange={(e) => setSipUser(e.target.value)}
/>
<label htmlFor="sip_password">
Password{" "}
{(sipUser || sipRegister || trunkType === "reg") && (
<span>*</span>
)}
</label>
<Passwd
id="sip_password"
name="sip_password"
value={sipPass}
placeholder="SIP password for authenticating outbound calls"
required={
trunkType === "reg" || sipRegister || sipUser.length > 0
}
onChange={(e) => setSipPass(e.target.value)}
/>
</>
);
if (trunkType === "reg") {
return (
<div>
<div className="label">Authentication</div>
<MS>
Registration trunk requires authentication credentials.
</MS>
{authFields}
</div>
);
} else {
return (
<Checkzone
key={`sip_credentials_${trunkType}`}
hidden
name="sip_credentials"
label="Authentication"
initialCheck={initialRegister}
handleChecked={(e) => {
if (!e.target.checked) {
setSipUser("");
setSipPass("");
setSipRegister(false);
}
}}
>
<MS>Does your carrier require authentication?</MS>
{authFields}
</Checkzone>
);
}
})()}
</fieldset>
<fieldset>
<Checkzone
hidden
name="sip_register"
label="Require SIP Register"
initialCheck={initialSipRegister}
handleChecked={(e) => {
setSipRegister(e.target.checked);
if (!e.target.checked) {
setSipRealm("");
setFromUser("");
setFromDomain("");
setRegPublicIpInContact(false);
}
}}
>
<MS>Carrier requires SIP Register.</MS>
<label htmlFor="sip_realm">
SIP realm
{sipRegister || trunkType === "reg" ? <span>*</span> : ""}
</label>
<input
id="sip_realm"
name="sip_realm"
type="text"
value={sipRealm}
placeholder="SIP realm for registration"
required={sipRegister || trunkType === "reg"}
onChange={(e) => setSipRealm(e.target.value)}
/>
<label htmlFor="from_user">Username</label>
<input
id="from_user"
name="from_user"
type="text"
value={fromUser}
placeholder="Optional: specify user part of SIP From header"
onChange={(e) => setFromUser(e.target.value)}
/>
<label htmlFor="from_domain">SIP from domain</label>
<input
id="from_domain"
name="from_domain"
type="text"
value={fromDomain}
placeholder="Optional: specify host part of SIP From header"
onChange={(e) => setFromDomain(e.target.value)}
/>
<label htmlFor="reg_public_ip_in_contact_2" className="chk">
<input
id="reg_public_ip_in_contact_2"
name="reg_public_ip_in_contact_2"
type="checkbox"
checked={regPublicIpInContact}
onChange={(e) => setRegPublicIpInContact(e.target.checked)}
/>
<div>Use public IP in contact</div>
</label>
</Checkzone>
{/* SIP Registration Fields - shared component */}
{(() => {
const sipRegFields = (
<>
<label htmlFor="sip_realm">
SIP realm{" "}
{(sipRegister || trunkType === "reg") && <span>*</span>}
</label>
<input
id="sip_realm"
name="sip_realm"
type="text"
value={sipRealm}
placeholder="SIP realm for registration"
required={trunkType === "reg" || sipRegister}
onChange={(e) => setSipRealm(e.target.value)}
/>
<label htmlFor="from_user">Username</label>
<input
id="from_user"
name="from_user"
type="text"
value={fromUser}
placeholder="Optional: specify user part of SIP From header"
onChange={(e) => setFromUser(e.target.value)}
/>
<label htmlFor="from_domain">SIP from domain</label>
<input
id="from_domain"
name="from_domain"
type="text"
value={fromDomain}
placeholder="Optional: specify host part of SIP From header"
onChange={(e) => setFromDomain(e.target.value)}
/>
<label htmlFor="reg_public_ip_in_contact" className="chk">
<input
id="reg_public_ip_in_contact"
name="reg_public_ip_in_contact"
type="checkbox"
checked={regPublicIpInContact}
onChange={(e) =>
setRegPublicIpInContact(e.target.checked)
}
/>
<div>Use public IP in contact</div>
</label>
</>
);
if (trunkType === "reg") {
return (
<div>
<div className="label">SIP Registration</div>
<MS>
Registration trunk requires SIP registration settings.
</MS>
{sipRegFields}
</div>
);
} else {
return (
<Checkzone
key={`sip_register_${trunkType}`}
hidden
name="sip_register"
label="Require SIP Register"
initialCheck={initialSipRegister}
handleChecked={(e) => {
setSipRegister(e.target.checked);
if (!e.target.checked) {
setSipRealm("");
setFromUser("");
setFromDomain("");
setRegPublicIpInContact(false);
}
}}
>
<MS>Carrier requires SIP Register.</MS>
{sipRegFields}
</Checkzone>
);
}
})()}
</fieldset>
<fieldset>
<Checkzone