From 64f3ed5786381e240241b202b28e5e9a5f9f8069 Mon Sep 17 00:00:00 2001 From: Pasindu Yeshan Date: Tue, 2 Jul 2024 14:03:49 +0530 Subject: [PATCH 01/31] Add support for multi-valued attributes. --- .../src/components/profile/profile.scss | 111 ++ .../src/components/profile/profile.tsx | 1530 ++++++++++++----- .../core/src/constants/profile-constants.ts | 2 + 3 files changed, 1210 insertions(+), 433 deletions(-) create mode 100644 apps/myaccount/src/components/profile/profile.scss diff --git a/apps/myaccount/src/components/profile/profile.scss b/apps/myaccount/src/components/profile/profile.scss new file mode 100644 index 00000000000..ea4b3eb4975 --- /dev/null +++ b/apps/myaccount/src/components/profile/profile.scss @@ -0,0 +1,111 @@ +.profile-form { + .multi-input-box { + width: 100%; + } + + .hidden { + display: none; + } + + .oxygen-accordion { + + .oxygen-accordion-summary { + display: flex; + padding: 0px 8px; + background-color: white; + flex-wrap: nowrap; + align-items: center; + gap: 4px; + + .accordion-label { + margin: 0 0 0 8px; + flex-shrink: 0; + padding-right: 12px; + } + + .verified-icon, .primary-icon { + display: flex; + align-items: center; + } + } + + .oxygen-accordion-details { + .multi-value-table { + .multi-value-table-data-row { + &:last-child td, &:last-child th { + border: none; + } + } + + .table-c1 { + display: flex; + flex-wrap: nowrap; + align-items: center; + + .c1-value{ + margin-bottom: 0; + flex-shrink: 0; + padding-right: 12px; + } + + .verified-icon, .primary-icon { + align-items: center; + } + } + + .table-c2 { + display: flex; + flex-wrap: nowrap; + align-items: center; + justify-content: flex-end; + gap: 4px; + } + } + } + + .MuiAccordionDetails-root { + padding: 0px; + } + + .MuiAccordionSummary-root { + min-height: 48px; + } + } + + .multi-attribute-dropdown { + width: 100%; + } +} + +.MuiMenuItem-root:hover { + background-color: transparent !important; +} + +.MuiMenuItem-root.Mui-selected, .MuiMenuItem-root.Mui-selected:hover { + background-color: transparent !important; +} + +.dropdown-row { + display: flex; + flex-wrap: nowrap; + align-items: center; + gap: 4px; + + .dropdown-label { + display: flex; + align-items: center; + padding-right: 8px; + margin: 0 !important; + } + + .verified-icon, .primary-icon { + align-items: center; + } +} + +.vertical-align-center { + display: flex; + flex-wrap: nowrap; + align-items: center; + height: 100%; +} diff --git a/apps/myaccount/src/components/profile/profile.tsx b/apps/myaccount/src/components/profile/profile.tsx index a22343c3f56..fe6dc153ca8 100644 --- a/apps/myaccount/src/components/profile/profile.tsx +++ b/apps/myaccount/src/components/profile/profile.tsx @@ -16,6 +16,29 @@ * under the License. */ +import Table from "@mui/material/Table"; +import TableBody from "@mui/material/TableBody"; +import TableCell from "@mui/material/TableCell"; +import TableContainer from "@mui/material/TableContainer"; +import TableRow from "@mui/material/TableRow"; +import ToggleButton from "@mui/material/ToggleButton"; +import ToggleButtonGroup from "@mui/material/ToggleButtonGroup"; +import Accordion from "@oxygen-ui/react/Accordion"; +import AccordionDetails from "@oxygen-ui/react/AccordionDetails"; +import AccordionSummary from "@oxygen-ui/react/AccordionSummary"; +import Button from "@oxygen-ui/react/Button"; +import Chip from "@oxygen-ui/react/Chip"; +import IconButton from "@oxygen-ui/react/IconButton"; +import InputAdornment from "@oxygen-ui/react/InputAdornment"; +import MenuItem from "@oxygen-ui/react/MenuItem"; +import Paper from "@oxygen-ui/react/Paper"; +import Select from "@oxygen-ui/react/Select"; +import Typography from "@oxygen-ui/react/Typography"; +// import ListItem from "@oxygen-ui/react/ListItem"; +// import ListItemButton from "@oxygen-ui/react/ListItemButton"; +// import ListItemIcon from "@oxygen-ui/react/ListItemIcon"; +// import ListItemText from "@oxygen-ui/react/ListItemText"; +import { CheckIcon, ChevronDownIcon } from "@oxygen-ui/react-icons"; import { ProfileConstants } from "@wso2is/core/constants"; import { IdentityAppsApiException } from "@wso2is/core/exceptions"; import { @@ -74,6 +97,14 @@ import { getProfileInformation, setActiveForm } from "../../store/actions"; import { CommonUtils } from "../../utils"; import { EditSection, SettingsSection } from "../shared"; import { MobileUpdateWizard } from "../shared/mobile-update-wizard"; +import "./profile.scss"; + +const EMAIL_ATTRIBUTE: string = "emails"; +const MOBILE_ATTRIBUTE: string = "mobile"; +const EMAIL_ADDRESSES_ATTRIBUTE: string = "emailAddresses"; +const MOBILE_NUMBERS_ATTRIBUTE: string = "mobileNumbers"; +const VERIFIED_MOBILE_NUMBERS_ATTRIBUTE: string = "verifiedMobileNumbers"; +const VERIFIED_EMAIL_ADDRESSES_ATTRIBUTE: string = "verifiedEmailAddresses"; /** * Prop types for the basic details component. @@ -127,6 +158,14 @@ export const Profile: FunctionComponent = (props: ProfileProps): R const [ isMobileVerificationEnabled, setIsMobileVerificationEnabled ] = useState(false); const [ isEmailVerificationEnabled, setIsEmailVerificationEnabled ] = useState(false); + const [ isMultipleEmailAndMobileNumberEnabled, setIsMultipleEmailAndMobileNumberEnabled ] = + useState(false); + const [ expandMultiAttributeAccordion, setExpandMultiAttributeAccordion ] = useState>({ + [EMAIL_ADDRESSES_ATTRIBUTE]: false, + [MOBILE_NUMBERS_ATTRIBUTE]: false + }); + const [ tempEmail, setTempEmail ] = useState(""); + const [ tempMobile, setTempMobile ] = useState(""); /** * The following method gets the preference for verification on mobile and email update. @@ -138,7 +177,8 @@ export const Profile: FunctionComponent = (props: ProfileProps): R "connector-name": ProfileConstants.USER_CLAIM_UPDATE_CONNECTOR, properties: [ ProfileConstants.ENABLE_EMAIL_VERIFICATION, - ProfileConstants.ENABLE_MOBILE_VERIFICATION + ProfileConstants.ENABLE_MOBILE_VERIFICATION, + ProfileConstants.ENABLE_MULTIPLE_EMAILS_AND_MOBILE_NUMBERS ] } ]; @@ -156,6 +196,9 @@ export const Profile: FunctionComponent = (props: ProfileProps): R if (prop.name === ProfileConstants.ENABLE_MOBILE_VERIFICATION) { setIsMobileVerificationEnabled(prop.value.toLowerCase() == "true"); } + if (prop.name === ProfileConstants.ENABLE_MULTIPLE_EMAILS_AND_MOBILE_NUMBERS) { + setIsMultipleEmailAndMobileNumberEnabled(prop.value.toLowerCase() == "true"); + } }); } else { onAlertFired({ @@ -483,6 +526,14 @@ export const Profile: FunctionComponent = (props: ProfileProps): R isCanonical = true; } + if (checkSchemaType(schema.name, EMAIL_ADDRESSES_ATTRIBUTE) + || checkSchemaType(schema.name, MOBILE_NUMBERS_ATTRIBUTE)) { + const newValues: string[] = resolveProfileInfoSchemaValue(schema)?.split(",") || []; + + newValues.push(values.get(formName) as string); + values.set(formName, newValues.join(",")); + } + if (ProfileUtils.isMultiValuedSchemaAttribute(profileSchema, schemaNames[0]) || schemaNames[0] === "phoneNumbers") { const attributeValues: string[] = []; @@ -674,6 +725,144 @@ export const Profile: FunctionComponent = (props: ProfileProps): R dispatch(setActiveForm(null)); }; + /** + * Verify an email address or mobile number. + * + * @param schema - Schema of the attribute + * @param value - Value of the attribute + */ + const handleVerify = (schema: ProfileSchema, value: string) => { + + const data: { + Operations: Array<{ op: string, value: Record> }>, + schemas: Array + } = { + Operations: [ + { + op: "replace", + value: {} + } + ], + schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ] + }; + + if (checkSchemaType(schema.name, EMAIL_ADDRESSES_ATTRIBUTE)) { + + const verifiedEmailList: string[] = profileInfo?.get(VERIFIED_EMAIL_ADDRESSES_ATTRIBUTE)?.split(",") || []; + + verifiedEmailList.push(value); + data.Operations[0].value = { + [schema.schemaId]: { + [VERIFIED_EMAIL_ADDRESSES_ATTRIBUTE]: verifiedEmailList.join(",") + } + }; + } else if (checkSchemaType(schema.name, MOBILE_NUMBERS_ATTRIBUTE)) { + + const verifiedMobileList: string[] = profileInfo?.get(VERIFIED_MOBILE_NUMBERS_ATTRIBUTE)?.split(",") || []; + + verifiedMobileList.push(value); + data.Operations[0].value = { + [schema.schemaId]: { + [VERIFIED_MOBILE_NUMBERS_ATTRIBUTE]: verifiedMobileList.join(",") + } + }; + } + updateProfileInfo(data).then((response: AxiosResponse) => { + if (response.status === 200) { + onAlertFired({ + description: t( + "myAccount:components.profile.notifications.updateProfileInfo.success.description" + ), + level: AlertLevels.SUCCESS, + message: t( + "myAccount:components.profile.notifications.updateProfileInfo.success.message" + ) + }); + + // Re-fetch the profile information + dispatch(getProfileInformation(true)); + } + }).catch((error: any) => { + onAlertFired({ + description: error?.detail ?? t( + "myAccount:components.profile.notifications.updateProfileInfo.genericError.description" + ), + level: AlertLevels.ERROR, + message: error?.message ?? t( + "myAccount:components.profile.notifications.updateProfileInfo.genericError.message" + ) + }); + }); + }; + + /** + * Delete a multi-valued attribute value. + * + * @param schema - schema of the attribute + * @param value - value of the attribute + */ + const handleMultiValuedItemDelete = (schema: ProfileSchema, value: string) => { + + const data: { + Operations: Array<{ op: string, value: Record> }>, + schemas: Array + } = { + Operations: [ + { + op: "replace", + value: {} + } + ], + schemas: [ "urn:ietf:params:scim:api:messages:2.0:PatchOp" ] + }; + + if (checkSchemaType(schema.name, EMAIL_ADDRESSES_ATTRIBUTE)) { + const emailList: string[] = profileInfo?.get(EMAIL_ADDRESSES_ATTRIBUTE)?.split(",") || []; + const updatedEmailList: string[] = emailList.filter((email: string) => email !== value); + + data.Operations[0].value = { + [schema.schemaId] : { + [EMAIL_ADDRESSES_ATTRIBUTE]: updatedEmailList.join(",") + } + }; + } else if (checkSchemaType(schema.name, MOBILE_NUMBERS_ATTRIBUTE)) { + const mobileList: string[] = profileInfo?.get(MOBILE_NUMBERS_ATTRIBUTE)?.split(",") || []; + const updatedMobileList: string[] = mobileList.filter((mobile: string) => mobile !== value); + + data.Operations[0].value = { + [schema.schemaId]: { + [MOBILE_NUMBERS_ATTRIBUTE]: updatedMobileList.join(",") + } + }; + } + updateProfileInfo(data).then((response: AxiosResponse) => { + if (response.status === 200) { + onAlertFired({ + description: t( + "myAccount:components.profile.notifications.updateProfileInfo.success.description" + ), + level: AlertLevels.SUCCESS, + message: t( + "myAccount:components.profile.notifications.updateProfileInfo.success.message" + ) + }); + + // Re-fetch the profile information + dispatch(getProfileInformation(true)); + } + }).catch((error: any) => { + onAlertFired({ + description: error?.detail ?? t( + "myAccount:components.profile.notifications.updateProfileInfo.genericError.description" + ), + level: AlertLevels.ERROR, + message: error?.message ?? t( + "myAccount:components.profile.notifications.updateProfileInfo.genericError.message" + ) + }); + }); + }; + /** * This takes the schema name and a type and sees if the schema is of the specified type * @param schema - The schema name eg: 'emails.workEmail' @@ -716,9 +905,21 @@ export const Profile: FunctionComponent = (props: ProfileProps): R * @param schema - Profile schemas. * @returns Schema form. */ - const generateSchemaForm = (schema: ProfileSchema): JSX.Element => { + const generateSchemaForm = (schema: ProfileSchema, index: number): JSX.Element => { + + // Define schemas to hide. + const attributesToHide: string[] = isMultipleEmailAndMobileNumberEnabled + ? [ EMAIL_ATTRIBUTE, MOBILE_ATTRIBUTE, VERIFIED_MOBILE_NUMBERS_ATTRIBUTE, + VERIFIED_EMAIL_ADDRESSES_ATTRIBUTE ] + : [ EMAIL_ADDRESSES_ATTRIBUTE, MOBILE_NUMBERS_ATTRIBUTE, + VERIFIED_MOBILE_NUMBERS_ATTRIBUTE, VERIFIED_EMAIL_ADDRESSES_ATTRIBUTE ]; + + // Hide the field if any of the relevant attributes match the schema name. + if (attributesToHide.some((name: string) => checkSchemaType(schema.name, name))) { + return; + } - /** + /* * Makes the "Username" field a READ_ONLY field. By default the * server SCIM2 endpoint sends it as a "READ_WRITE" property. * We are able to enable/disable read-only mode for specific @@ -747,454 +948,923 @@ export const Profile: FunctionComponent = (props: ProfileProps): R } } - /** - * Makes the email field read-only for users without local credentials - */ + // Makes the email field read-only for users without local credentials if (isNonLocalCredentialUser) { - if (name?.toLowerCase() === "emails" ) { + if (name?.toLowerCase() === EMAIL_ADDRESSES_ATTRIBUTE) { schema.mutability = ProfileConstants.READONLY_SCHEMA; } } - if (activeForm === CommonConstants.PERSONAL_INFO+schema.name) { - const fieldName: string = t("myAccount:components.profile.fields." + schema.displayName, - { defaultValue: schema.displayName } - ); - - // Define the field placeholder for text fields. - let innerPlaceholder: string = t("myAccount:components.profile.forms.generic." + - "inputs.placeholder", - { - fieldName: fieldName.toLowerCase() - } ); - - // Concatenate the date format for the birth date field. - if (schema.name === ProfileConstants.SCIM2_SCHEMA_DICTIONARY.get("DOB")) { - innerPlaceholder += " in the format YYYY-MM-DD"; - } + const fieldName: string = getFieldName(schema); + if (activeForm === CommonConstants.PERSONAL_INFO + schema.name) { return ( - isFeatureEnabled( - featureConfig?.personalInfo, - AppConstants.FEATURE_DICTIONARY.get("PROFILEINFO_MOBILE_VERIFICATION") - ) && checkSchemaType(schema.name, "mobile") - && isMobileVerificationEnabled - ? ( - -

- { t("myAccount:components.profile.messages.mobileVerification.content") } -

- - - < Grid.Column mobile={ 6 } tablet={ 6 } computer={ 4 } className="first-column"> - { fieldName } - - - - - { - isProfileInfoLoading || profileSchemaLoader - ? ( - - ) - : profileInfo.get(schema.name) - || ( - { - setShowMobileUpdateWizard(true); - } } - onKeyPress={ ( - { key }: React.KeyboardEvent - ) => - { - if (key === "Enter") { - setShowMobileUpdateWizard(true); - } - } - } - data-testid={ - `${testId}-schema-mobile-editing-section-${ - schema.name.replace(".", "-") - }-placeholder` - } - > - { t("myAccount:components.profile.forms.generic." + - "inputs.placeholder", { - fieldName: fieldName.toLowerCase() }) - } - - ) - } - - - - - - - { - setShowMobileUpdateWizard(true); - } } - > - { t("common:update").toString() } - - - - { - dispatch(setActiveForm(null)); - } } - > - { t("common:cancel").toString() } - - - - -
- ) - : ( - - - - { fieldName } - - ) => { - handleSubmit(values, schema.name, schema.extended, schema); - } } - > - { checkSchemaType(schema.name, "country") ? ( - { - return { - "data-testid": `${testId}-${list.value as string}`, - flag: list.flag, - key: list.key as string, - text: list.text as string, - value: list.value as string - }; - }) : [] } - value={ resolveProfileInfoSchemaValue(schema) } - disabled={ false } - clearable={ !schema.required } - search - selection - fluid - /> - ) : ( - { - if (!RegExp(schema.regEx).test(value)) { - validation.isValid = false; - if (checkSchemaType(schema.name, "emails")) { - validation.errorMessages.push( - t("myAccount:components.profile.forms." + - "emailChangeForm.inputs.email.validations." + - "invalidFormat") - ); - } else if (checkSchemaType(schema.name, ProfileConstants. - SCIM2_SCHEMA_DICTIONARY.get("PHONE_NUMBERS"))) { - validation.errorMessages.push(t( - profileConfig?.attributes?. - getRegExpValidationError( - ProfileConstants.SCIM2_SCHEMA_DICTIONARY - .get("PHONE_NUMBERS") - ), - { - fieldName - } - ) - ); - } else if (checkSchemaType(schema.name, - ProfileConstants.SCIM2_SCHEMA_DICTIONARY.get("DOB"))) { - validation.errorMessages.push( - t("myAccount:components.profile.forms." + - "dateChangeForm.inputs.date.validations." + - "invalidFormat", { fieldName }) - ); - } else { - validation.errorMessages.push( - t( - "myAccount:components.profile.forms." + - "generic.inputs.validations.invalidFormat", - { - fieldName - } - ) - ); - } - // Validate date format and the date is before the current date - } else if(checkSchemaType(schema.name, - ProfileConstants.SCIM2_SCHEMA_DICTIONARY.get("DOB"))){ - if (!moment(value, "YYYY-MM-DD",true).isValid()) { - validation.isValid = false; - validation.errorMessages - .push(t("myAccount:components.profile.forms." - + "dateChangeForm.inputs.date.validations." - + "invalidFormat", { - field: fieldName - })); - } else { - if (moment().isBefore(value)) { - validation.isValid = false; - validation.errorMessages - .push(t("myAccount:components.profile.forms." - + "dateChangeForm.inputs.date.validations." - + "futureDateError", { - field: fieldName - })); - } - } - } - } } - value={ resolveProfileInfoSchemaValue(schema) } - maxLength={ - schema.name === "emails" - ? 50 - : ( - fieldName.toLowerCase().includes("uri") - || fieldName.toLowerCase().includes("url") - ) - ? 1024 - : ( - schema.maxLength - ? schema.maxLength - : ProfileConstants.CLAIM_VALUE_MAX_LENGTH - ) - } - /> - ) - } - - - - - ) + + { generateSingleMobileVerificationSection(schema, fieldName) + || generateEditableForm(schema, fieldName) } + ); } else { - const fieldName: string = t("myAccount:components.profile.fields." + schema.displayName, - { defaultValue: schema.displayName } + return ( + + { generateReadOnlyForm(schema, fieldName) } + ); + } + }; - return ( + /** + * This function generate mobile verification section for mobile schema. + * + * @param schema - The schema to generate the form for. + * @param fieldName - The field name to get the placeholder text for. + * @returns Mobile verification section. + */ + const generateSingleMobileVerificationSection = (schema: ProfileSchema, fieldName: string) => { + + if (!isFeatureEnabled( + featureConfig?.personalInfo, + AppConstants.FEATURE_DICTIONARY.get("PROFILEINFO_MOBILE_VERIFICATION") + ) || !checkSchemaType(schema.name, MOBILE_ATTRIBUTE) || !isMobileVerificationEnabled) { + return null; + } + + return ( + +

{ t("myAccount:components.profile.messages.mobileVerification.content") }

- - < Grid.Column mobile={ 6 } tablet={ 6 } computer={ 4 } className="first-column"> - - { - !showEmail && fieldName.toLowerCase() === "username" - ? fieldName + " (Email)" - : fieldName - } - + + + { fieldName } - { - isProfileInfoLoading || profileSchemaLoader - ? ( - - ) - : profileInfo.get(schema.name) - ? ( - schema.name === ProfileConstants.SCIM2_SCHEMA_DICTIONARY - .get("EMAILS") && isEmailPending && isEmailVerificationEnabled - ? ( - <> -

- { - profileInfo.get(schema.name) + { isProfileInfoLoading || profileSchemaLoader + ? + : profileInfo.get(schema.name) + || ( + { + setShowMobileUpdateWizard(true); + } } + onKeyPress={ ( + { key }: React.KeyboardEvent + ) => + { + if (key === "Enter") { + setShowMobileUpdateWizard(true); + } + } + } + data-testid={ + `${testId}-schema-mobile-editing-section-${ + schema.name.replace(".", "-") + }-placeholder` + } + > + { t("myAccount:components.profile.forms.generic." + + "inputs.placeholder", { + fieldName: fieldName.toLowerCase() }) + } + + ) + + } + + + + + + + setShowMobileUpdateWizard(true) }> + { t("common:update").toString() } + + + + dispatch(setActiveForm(null)) }> + { t("common:cancel").toString() } + + + + + + ); + }; + + /** + * This function generates the editable form for the schema. + * + * @param schema - The schema to generate the form for. + * @returns The editable form. + */ + const generateEditableForm = (schema: ProfileSchema, fieldName: string): JSX.Element => { + + return ( + + + + { fieldName } + + ) => + handleSubmit(values, schema.name, schema.extended, schema) }> + { generateFormFields(schema, fieldName) } + + + + + + ); + }; + + /** + * This function generates the read-only form for the schema. + * + * @param schema - The schema to generate the form for. + * @returns The read-only form. + */ + const generateReadOnlyForm = (schema: ProfileSchema, fieldName: string): JSX.Element => { + + return ( + + + + { + !showEmail && fieldName.toLowerCase() === "username" + ? fieldName + " (Email)" + : fieldName } + + + + + + { generateReadOnlyFieldContent(schema, fieldName) } + + + + + + { generateEditIcon(schema) } + + + + + ); + }; + + /** + * This function generates the form fields for the schema. + * + * @param schema - The schema to generate the form fields for. + * @param fieldName - The field name to generate the form fields for. + * @returns The form fields. + */ + const generateFormFields = (schema: ProfileSchema, fieldName: string): JSX.Element => { + + if (checkSchemaType(schema.name, "country")) { + return generateCountryDropdown(schema, fieldName); + } else if (checkSchemaType(schema.name, EMAIL_ADDRESSES_ATTRIBUTE) + || checkSchemaType(schema.name, MOBILE_NUMBERS_ATTRIBUTE)) { + return generateMultiValuedField(schema, fieldName); + } else { + return generateTextField(schema, fieldName); + } + }; + + const generateMultiValuedField = (schema: ProfileSchema, fieldName: string): JSX.Element => { + + let primaryAttributeSchemaName: string = EMAIL_ATTRIBUTE; + let primaryAttributeSchema: ProfileSchema; + let attributeValueList: string[] = []; + let verifiedAttributeValueList: string[] = []; + let primaryAttributeValue: string = ""; + let verificationEnabled: boolean = false; + let deletePopupHeader: string = ""; + let verifyPopupHeader: string = ""; + + if (checkSchemaType(schema.name, EMAIL_ADDRESSES_ATTRIBUTE)) { + deletePopupHeader = "Delete Email Address"; + verifyPopupHeader = "Verify Email Address"; + attributeValueList = profileInfo.get(EMAIL_ADDRESSES_ATTRIBUTE)?.split(",") ?? []; + verifiedAttributeValueList = profileInfo.get(VERIFIED_EMAIL_ADDRESSES_ATTRIBUTE)?.split(",") ?? []; + primaryAttributeSchemaName = EMAIL_ATTRIBUTE; + primaryAttributeValue = profileInfo.get(primaryAttributeSchemaName); + verificationEnabled = isEmailVerificationEnabled; + primaryAttributeSchema = getSchemaFromName(EMAIL_ATTRIBUTE); + verifiedAttributeValueList.push(primaryAttributeValue); + + } else if (checkSchemaType(schema.name, MOBILE_NUMBERS_ATTRIBUTE)) { + deletePopupHeader = "Delete Mobile Number"; + verifyPopupHeader = "Verify Mobile Number"; + attributeValueList = profileInfo.get(MOBILE_NUMBERS_ATTRIBUTE)?.split(",") ?? []; + verifiedAttributeValueList = profileInfo.get(VERIFIED_MOBILE_NUMBERS_ATTRIBUTE)?.split(",") ?? []; + primaryAttributeSchemaName = MOBILE_ATTRIBUTE; + primaryAttributeValue = profileInfo.get(primaryAttributeSchemaName); + verificationEnabled = isMobileVerificationEnabled; + primaryAttributeSchema = getSchemaFromName(MOBILE_ATTRIBUTE); + verifiedAttributeValueList.push("0777453588"); + } + + // Move the primary attribute value to the top of the list. + if (primaryAttributeValue) { + attributeValueList = attributeValueList.filter((value: string) => value !== primaryAttributeValue); + attributeValueList.unshift(primaryAttributeValue); + } + + const showAccordion: boolean = attributeValueList.length >= 1; + const accordionLabelValue: string = primaryAttributeValue ?? attributeValueList[0]; + + return ( + <> + ) => { + if (checkSchemaType(schema.name, EMAIL_ADDRESSES_ATTRIBUTE)) { + setTempEmail(event.target.value); + } else { + setTempMobile(event.target.value); + } + } } + validation={ + (value: string, validation: Validation) => + validateField(value, validation, schema, fieldName) } + value={ checkSchemaType(schema.name, EMAIL_ADDRESSES_ATTRIBUTE) ? tempEmail : tempMobile } + maxLength={ + // TODO: Remove the hard-coded value and get it from the schema. + checkSchemaType(schema.name, EMAIL_ADDRESSES_ATTRIBUTE) + ? 50 + : primaryAttributeSchema.maxLength ?? ProfileConstants.CLAIM_VALUE_MAX_LENGTH + } + /> +

+ + ); + }; + + const generateCountryDropdown = (schema: ProfileSchema, fieldName: string): JSX.Element => { + + return ( + <> + ({ + "data-testid": `${testId}-${list.value as string}`, + flag: list.flag, + key: list.key as string, + text: list.text as string, + value: list.value as string + })) : [] } + value={ resolveProfileInfoSchemaValue(schema) } + disabled={ false } + clearable={ !schema.required } + search + selection + fluid + /> +