-
-
-
-
- <%-- product-footer --%>
- <%
- File productFooterFile = new File(getServletContext().getRealPath("extensions/product-footer.jsp"));
- if (productFooterFile.exists()) {
- %>
-
- <% } else { %>
-
- <% } %>
-
-
-
-
-
-
- <%-- footer --%>
- <%
- File footerFile = new File(getServletContext().getRealPath("extensions/footer.jsp"));
- if (footerFile.exists()) {
- %>
-
- <% } else { %>
-
- <% } %>
-
-
-
-
-
-
-
-
-
diff --git a/identity-apps-core/apps/authentication-portal/src/main/webapp/data/emailotp-submit-1-response.json b/identity-apps-core/apps/authentication-portal/src/main/webapp/data/emailotp-submit-1-response.json
new file mode 100644
index 00000000000..cfb7da0d353
--- /dev/null
+++ b/identity-apps-core/apps/authentication-portal/src/main/webapp/data/emailotp-submit-1-response.json
@@ -0,0 +1,67 @@
+{
+ "flowId": "d13ec8d2-2d1e-11ee-be56-0242ac120002",
+ "flowStatus": "INCOMPLETE",
+ "flowType": "REGISTRATION",
+ "elements": [
+ {
+ "id": "flow-display-header-8uJ6t4D3",
+ "category": "DISPLAY",
+ "type": "TYPOGRAPHY",
+ "variant": "H3",
+ "properties": {
+ "className": "wso2is-typography-h3",
+ "text": "sign.up.form.email.title",
+ "styles": {
+ "textAlign": "center"
+ }
+ }
+ },
+ {
+ "id": "flow-field-email-Rt8uJ6D3",
+ "category": "FIELD",
+ "type": "INPUT",
+ "variant": "TEXT",
+ "properties": {
+ "type": "email",
+ "label": "sign.up.form.fields.email.label",
+ "placeholder": "sign.up.form.fields.email.placeholder",
+ "name": "email",
+ "className": "wso2is-email-input",
+ "hint": "",
+ "dataType": "string",
+ "isRequired": true,
+ "isReadOnly": false,
+ "validationRegex": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
+ "multiline": false
+ }
+ },
+ {
+ "id": "flow-action-verify-otp-ssd5g6h",
+ "category": "ACTION",
+ "type": "BUTTON",
+ "variant": "PRIMARY",
+ "action": {
+ "type": "NAVIGATOR",
+ "name": "EmailOTPVerifier2"
+ },
+ "properties": {
+ "type": "submit",
+ "className": "wso2is-button",
+ "text": "sign.up.form.button.continue",
+ "action": "submit",
+ "styles": {
+ "width": "100%"
+ }
+ }
+ }
+ ],
+ "blocks": [
+ {
+ "id": "flow-block-attributes-g55dfGuKl",
+ "nodes": [
+ "flow-field-email-Rt8uJ6D3",
+ "flow-action-verify-otp-ssd5g6h"
+ ]
+ }
+ ]
+}
diff --git a/identity-apps-core/apps/authentication-portal/src/main/webapp/data/emailotp-submit-2-response.json b/identity-apps-core/apps/authentication-portal/src/main/webapp/data/emailotp-submit-2-response.json
new file mode 100644
index 00000000000..cf0e39602d2
--- /dev/null
+++ b/identity-apps-core/apps/authentication-portal/src/main/webapp/data/emailotp-submit-2-response.json
@@ -0,0 +1,86 @@
+{
+ "flowId": "d13ec8d2-2d1e-11ee-be56-0242ac120002",
+ "flowStatus": "INCOMPLETE",
+ "flowType": "REGISTRATION",
+ "elements": [
+ {
+ "id": "flow-display-header-8uJ6t4D3",
+ "category": "DISPLAY",
+ "type": "TYPOGRAPHY",
+ "variant": "H3",
+ "properties": {
+ "className": "wso2is-typography-h3",
+ "text": "sign.up.form.email.otp.title",
+ "styles": {
+ "textAlign": "center"
+ }
+ }
+ },
+ {
+ "id": "flow-field-otp-mn44gh0j",
+ "category": "FIELD",
+ "type": "INPUT",
+ "variant": "OTP",
+ "config": {
+ "userEmail": "nipunib@wso2.com"
+ },
+ "properties": {
+ "type": "text",
+ "label": "sign.up.form.fields.emailotp.label",
+ "name": "emailOTP",
+ "dataType": "string",
+ "isMandatory": true,
+ "isReadOnly": false,
+ "validationRegex": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
+ },
+ "styles": {}
+ },
+ {
+ "id": "flow-field-email-Rt8uJ6D3",
+ "category": "FIELD",
+ "type": "INPUT",
+ "variant": "EMAIL",
+ "properties": {
+ "type": "email",
+ "label": "sign.up.form.fields.email.label",
+ "placeholder": "sign.up.form.fields.email.placeholder",
+ "name": "email",
+ "className": "wso2is-email-input",
+ "hint": "",
+ "dataType": "string",
+ "isRequired": true,
+ "isReadOnly": false,
+ "validationRegex": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
+ "multiline": false
+ }
+ },
+ {
+ "id": "flow-action-verify-otp-ssd5g6h",
+ "category": "ACTION",
+ "type": "BUTTON",
+ "variant": "PRIMARY",
+ "action": {
+ "type": "NAVIGATOR",
+ "name": "EmailOTPVerifier3"
+ },
+ "properties": {
+ "type": "submit",
+ "className": "wso2is-button",
+ "text": "sign.up.form.button.submit",
+ "action": "submit",
+ "styles": {
+ "width": "100%"
+ }
+ }
+ }
+ ],
+ "blocks": [
+ {
+ "id": "flow-block-attributes-g55dfGuKl",
+ "nodes": [
+ "flow-field-otp-mn44gh0j",
+ "flow-action-verify-otp-ssd5g6h"
+ ]
+ }
+ ]
+}
diff --git a/identity-apps-core/apps/authentication-portal/src/main/webapp/data/init-response.json b/identity-apps-core/apps/authentication-portal/src/main/webapp/data/init-response.json
new file mode 100644
index 00000000000..e6171e71d4c
--- /dev/null
+++ b/identity-apps-core/apps/authentication-portal/src/main/webapp/data/init-response.json
@@ -0,0 +1,170 @@
+{
+ "flowId": "d13ec8d2-2d1e-11ee-be56-0242ac120002",
+ "flowStatus": "INCOMPLETE",
+ "flowType": "REGISTRATION",
+ "elements": [
+ {
+ "id": "flow-display-header-8uJ6t4D3",
+ "category": "DISPLAY",
+ "type": "TYPOGRAPHY",
+ "variant": "H3",
+ "properties": {
+ "className": "wso2is-typography-h3",
+ "text": "sign.up.form.title",
+ "styles": {
+ "textAlign": "center"
+ }
+ }
+ },
+ {
+ "id": "flow-field-username-Rt8uJ6D3",
+ "category": "FIELD",
+ "type": "INPUT",
+ "variant": "TEXT",
+ "properties": {
+ "type": "text",
+ "className": "wso2is-username-input",
+ "label": "sign.up.form.fields.username.label",
+ "hint": "",
+ "placeholder": "sign.up.form.fields.username.placeholder",
+ "name": "username",
+ "dataType": "string",
+ "required": true,
+ "readOnly": false,
+ "validationRegex": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"
+ }
+ },
+ {
+ "id": "flow-field-first-name-r7u4F1GG",
+ "category": "FIELD",
+ "type": "INPUT",
+ "variant": "TEXT",
+ "properties": {
+ "type": "text",
+ "name": "firstName",
+ "className": "wso2is-text-input",
+ "hint": "",
+ "label": "sign.up.form.fields.firstName.label",
+ "required": false,
+ "multiline": false,
+ "placeholder": "sign.up.form.fields.firstName.placeholder",
+ "defaultValue": "",
+ "minLength": 3,
+ "maxLength": 50,
+ "styles": {}
+ }
+ },
+ {
+ "id": "flow-field-last-name-r7u4F1GG",
+ "category": "FIELD",
+ "type": "INPUT",
+ "variant": "TEXT",
+ "properties": {
+ "type": "text",
+ "name": "lastName",
+ "className": "wso2is-text-input",
+ "hint": "",
+ "label": "sign.up.form.fields.lastName.label",
+ "required": false,
+ "multiline": false,
+ "placeholder": "sign.up.form.fields.lastName.placeholder",
+ "defaultValue": "",
+ "minLength": 3,
+ "maxLength": 50,
+ "styles": {}
+ }
+ },
+ {
+ "id": "flow-action-password-onboarder-p563u9Yn",
+ "category": "ACTION",
+ "type": "BUTTON",
+ "variant": "PRIMARY",
+ "action": {
+ "type": "EXECUTOR",
+ "name": "PasswordOnboarder"
+ },
+ "properties": {
+ "type": "submit",
+ "className": "wso2is-button",
+ "text": "sign.up.form.button.continue.with.password",
+ "styles": {
+ "width": "100%"
+ }
+ }
+ },
+ {
+ "id": "flow-display-horizontal-divider-67f8uJ6D3",
+ "category": "DISPLAY",
+ "type": "DIVIDER",
+ "version": "0.1.0",
+ "variant": "HORIZONTAL",
+ "properties": {
+ "className": "wso2is-divider-horizontal",
+ "text": "Or",
+ "styles": {}
+ }
+ },
+ {
+ "id": "flow-action-email-otp-verifier-5t8uJ6D3",
+ "category": "ACTION",
+ "type": "BUTTON",
+ "deprecated": false,
+ "variant": "PRIMARY",
+ "action": {
+ "type": "EXECUTOR",
+ "name": "EmailOTPVerifier1"
+ },
+ "properties": {
+ "type": "submit",
+ "className": "wso2is-button",
+ "text": "sign.up.form.button.continue.with.email.otp",
+ "styles": {
+ "width": "100%"
+ }
+ }
+ },
+ {
+ "id": "flow-display-horizontal-divider-67f8uJ6D4",
+ "category": "DISPLAY",
+ "type": "DIVIDER",
+ "variant": "HORIZONTAL",
+ "properties": {
+ "className": "wso2is-divider-horizontal",
+ "text": "Or",
+ "styles": {}
+ }
+ },
+ {
+ "id": "flow-action-google-sign-up-Rt8uJ6D3",
+ "category": "ACTION",
+ "type": "BUTTON",
+ "deprecated": false,
+ "variant": "SOCIAL_BUTTON",
+ "action": {
+ "type": "EXECUTOR",
+ "name": "GoogleSignUp"
+ },
+ "properties": {
+ "type": "button",
+ "className": "wso2is-social-button",
+ "text": "sign.up.form.button.continue.with.google",
+ "styles": {
+ "width": "100%"
+ }
+ }
+ }
+ ],
+ "blocks": [
+ {
+ "id": "flow-block-attributes-g55dfGuK",
+ "nodes": [
+ "flow-field-username-Rt8uJ6D3",
+ "flow-field-first-name-r7u4F1GG",
+ "flow-field-last-name-r7u4F1GG",
+ "flow-action-password-onboarder-p563u9Yn",
+ "flow-display-horizontal-divider-67f8uJ6D3",
+ "flow-action-email-otp-verifier-5t8uJ6D3"
+ ]
+ }
+ ]
+}
diff --git a/identity-apps-core/apps/authentication-portal/src/main/webapp/data/password-submit-response.json b/identity-apps-core/apps/authentication-portal/src/main/webapp/data/password-submit-response.json
new file mode 100644
index 00000000000..355621501da
--- /dev/null
+++ b/identity-apps-core/apps/authentication-portal/src/main/webapp/data/password-submit-response.json
@@ -0,0 +1,175 @@
+{
+ "flowId": "d13ec8d2-2d1e-11ee-be56-0242ac120002",
+ "flowStatus": "INCOMPLETE",
+ "flowType": "REGISTRATION",
+ "elements": [
+ {
+ "id": "flow-display-header-8uJ6t4D3",
+ "category": "DISPLAY",
+ "type": "TYPOGRAPHY",
+ "variant": "H3",
+ "properties": {
+ "className": "wso2is-typography-h3",
+ "text": "sign.up.form.password.title",
+ "styles": {
+ "textAlign": "center"
+ }
+ }
+ },
+ {
+ "id": "flow-field-password-Rt8uJ6D3",
+ "category": "FIELD",
+ "type": "INPUT",
+ "variant": "PASSWORD",
+ "properties": {
+ "type": "password",
+ "label": "sign.up.form.fields.password.label",
+ "placeholder": "sign.up.form.fields.password.placeholder",
+ "name": "password",
+ "dataType": "string",
+ "required": true,
+ "isReadOnly": false,
+ "validation": [
+ {
+ "type": "CRITERIA",
+ "showValidationCriteria": true,
+ "criteria": [
+ {
+ "label": "sign.up.form.fields.password.policies.length",
+ "error": "This field must be between 5 and 10 characters.",
+ "validation": [
+ {
+ "type": "MIN_LENGTH",
+ "value": 5,
+ "error": "This field must be at least 5 characters."
+ },
+ {
+ "type": "MAX_LENGTH",
+ "value": 10,
+ "error": "This field must be at most 10 characters."
+ }
+ ]
+ },
+ {
+ "label": "sign.up.form.fields.password.policies.lowercaseAndUppercaseLetter",
+ "error": "This field must have at least one uppercase and lowercase letter.",
+ "validation": [
+ {
+ "type": "MIN_LOWERCASE_LETTERS",
+ "value": 1,
+ "error": "Password must contain at least one lowercase letter."
+ },
+ {
+ "type": "MIN_UPPERCASE_LETTERS",
+ "value": 1,
+ "error": "Password must contain at least one uppercase letter."
+ }
+ ]
+ },
+ {
+ "label": "sign.up.form.fields.password.policies.minimumOneNumber",
+ "error": "This field must have at least one number.",
+ "validation": [
+ {
+ "type": "MIN_NUMBERS",
+ "value": 1,
+ "error": "Password must contain at least one number."
+ }
+ ]
+ },
+ {
+ "label": "sign.up.form.fields.password.policies.minimumOneSpecialCharacter",
+ "error": "This field must have at least one special character.",
+ "validation": [
+ {
+ "type": "MIN_SPECIAL_CHARACTERS",
+ "value": 1,
+ "error": "Password must contain at least one special character."
+ }
+ ]
+ },
+ {
+ "label": "sign.up.form.fields.password.policies.minimumOneSpecialCharacter",
+ "error": "This field must have at least one special character.",
+ "validation": [
+ {
+ "type": "MIN_SPECIAL_CHARACTERS",
+ "value": 1,
+ "error": "Password must contain at least one special character."
+ }
+ ]
+ },
+ {
+ "label": "sign.up.form.fields.password.policies.minimumOneUniqueCharacter",
+ "error": "This field must have at least one unique character.",
+ "validation": [
+ {
+ "type": "MIN_UNIQUE_CHARACTERS",
+ "value": 1,
+ "error": "Password must contain at least one unique character."
+ }
+ ]
+ },
+ {
+ "label": "sign.up.form.fields.password.policies.noRepeatedCharacters",
+ "error": "This field must not have repeated characters.",
+ "validation": [
+ {
+ "type": "MAX_REPEATED_CHARACTERS",
+ "value": 0,
+ "error": "Password must not contain repeated characters."
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "id": "flow-field-confirm-password-Rt8uJ6D4",
+ "category": "FIELD",
+ "type": "INPUT",
+ "variant": "PASSWORD",
+ "properties": {
+ "type": "password",
+ "label": "sign.up.form.fields.confirmPassword",
+ "placeholder": "sign.up.form.fields.confirmPassword.placeholder",
+ "name": "confirmPassword",
+ "dataType": "string",
+ "isMandatory": true,
+ "isReadOnly": false,
+ "validationRegex": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
+ "showValidationCriteria": false
+ }
+ },
+ {
+ "id": "flow-action-password-submit-p563u9Yn",
+ "category": "ACTION",
+ "type": "BUTTON",
+ "variant": "PRIMARY",
+ "action": {
+ "type": "NAVIGATOR",
+ "name": "PasswordOnboarder"
+ },
+ "properties": {
+ "type": "submit",
+ "className": "wso2is-button",
+ "text": "sign.up.form.button.register",
+ "styles": {
+ "width": "100%"
+ }
+ }
+ }
+ ],
+ "blocks": [
+ {
+ "id": "flow-block-attributes-g55dfGoK",
+ "nodes": [
+ "flow-field-password-Rt8uJ6D3",
+ "flow-field-confirm-password-Rt8uJ6D4",
+ "flow-action-password-submit-p563u9Yn"
+ ]
+ }
+ ]
+}
diff --git a/identity-apps-core/apps/authentication-portal/src/main/webapp/i18n/translations/en-US.json b/identity-apps-core/apps/authentication-portal/src/main/webapp/i18n/translations/en-US.json
new file mode 100644
index 00000000000..81fa8440ebc
--- /dev/null
+++ b/identity-apps-core/apps/authentication-portal/src/main/webapp/i18n/translations/en-US.json
@@ -0,0 +1,32 @@
+{
+ "sign.up.form.title": "Sign Up",
+ "sign.up.form.password.title": "Enter Your Password",
+ "sign.up.form.email.title": "Enter Your Email",
+ "sign.up.form.email.otp.title": "OTP Verification",
+ "sign.up.form.fields.username.label": "Username",
+ "sign.up.form.fields.username.placeholder": "Enter your username",
+ "sign.up.form.fields.email.label": "Email",
+ "sign.up.form.fields.email.placeholder": "Enter your email",
+ "sign.up.form.fields.password.label": "Password",
+ "sign.up.form.fields.password.placeholder": "Enter your password",
+ "sign.up.form.fields.confirmPassword": "Confirm Password",
+ "sign.up.form.fields.confirmPassword.placeholder": "Re-enter your password",
+ "sign.up.form.fields.password.policies.length": "More than 8 characters",
+ "sign.up.form.fields.password.policies.lowercaseAndUppercaseLetter": "At least one uppercase and lowercase letter",
+ "sign.up.form.fields.password.policies.minimumOneNumber": "At least one number",
+ "sign.up.form.fields.password.policies.minimumOneSpecialCharacter": "At least one special character",
+ "sign.up.form.fields.password.policies.minimumOneUniqueCharacter": "At least one unique character",
+ "sign.up.form.fields.password.policies.noRepeatedCharacters": "No more than one repeated character",
+ "sign.up.form.fields.firstName.label": "First Name",
+ "sign.up.form.fields.firstName.placeholder": "Enter your first name",
+ "sign.up.form.fields.lastName.label": "Last Name",
+ "sign.up.form.fields.lastName.placeholder": "Enter your last name",
+ "sign.up.form.fields.smsotp.label": "Enter the code sent to your mobile phone:",
+ "sign.up.form.fields.emailotp.label": "Enter the code sent to your email:",
+ "sign.up.form.button.continue.with.password": "Continue with Password",
+ "sign.up.form.button.continue.with.email.otp": "Continue with Email OTP",
+ "sign.up.form.button.continue.with.google": "Continue with Google",
+ "sign.up.form.button.register": "Register",
+ "sign.up.form.button.submit": "Submit",
+ "sign.up.form.button.continue": "Continue"
+}
diff --git a/identity-apps-core/apps/authentication-portal/src/main/webapp/self-registration.jsp b/identity-apps-core/apps/authentication-portal/src/main/webapp/self-registration.jsp
new file mode 100644
index 00000000000..9d7e55e83a0
--- /dev/null
+++ b/identity-apps-core/apps/authentication-portal/src/main/webapp/self-registration.jsp
@@ -0,0 +1,239 @@
+<%--
+ ~ Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ ~
+ ~ WSO2 LLC. licenses this file to you under the Apache License,
+ ~ Version 2.0 (the "License"); you may not use this file except
+ ~ in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+--%>
+
+<%@ page import="org.owasp.encoder.Encode" %>
+<%@ page import="java.io.File" %>
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
+<%@ page import="java.nio.file.Files, java.nio.file.Paths, java.io.IOException" %>
+<%@ page import="org.wso2.carbon.identity.mgt.endpoint.util.client.SelfRegistrationMgtClient" %>
+
+<%@ taglib prefix="layout" uri="org.wso2.identity.apps.taglibs.layout.controller" %>
+
+<%@include file="includes/localize.jsp" %>
+<%@include file="includes/init-url.jsp" %>
+
+<%-- Branding Preferences --%>
+
+
+<%-- Data for the layout from the page --%>
+<%
+ layoutData.put("containerSize", "medium");
+%>
+
+
+<%
+ String local = "en-US";
+ String jsonFilePath = application.getRealPath("/i18n/translations/" + local + ".json");
+ String translationsJson = "{}";
+
+ try {
+ byte[] jsonData = Files.readAllBytes(Paths.get(jsonFilePath));
+ translationsJson = new String(jsonData, "UTF-8");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+%>
+
+
+
+
+ <%-- header --%>
+ <%
+ File headerFile = new File(getServletContext().getRealPath("extensions/header.jsp"));
+ if (headerFile.exists()) {
+ %>
+
+ <% } else { %>
+
+ <% } %>
+
+
+
+
+
+
+
+
+ <%-- product-title --%>
+ <%
+ File productTitleFile = new File(getServletContext().getRealPath("extensions/product-title.jsp"));
+ if (productTitleFile.exists()) {
+ %>
+
+ <% } else { %>
+
+ <% } %>
+
+
+
+
+
+
+
+ <%-- product-footer --%>
+ <%
+ File productFooterFile = new File(getServletContext().getRealPath("extensions/product-footer.jsp"));
+ if (productFooterFile.exists()) {
+ %>
+
+ <% } else { %>
+
+ <% } %>
+
+
+
+
+
+
+ <%-- footer --%>
+ <%
+ File footerFile = new File(getServletContext().getRealPath("extensions/footer.jsp"));
+ if (footerFile.exists()) {
+ %>
+
+ <% } else { %>
+
+ <% } %>
+
+
+
+
+
+
+
+
diff --git a/identity-apps-core/apps/authentication-portal/src/main/webapp/util/create-account-api.jsp b/identity-apps-core/apps/authentication-portal/src/main/webapp/util/self-registration-api.jsp
similarity index 65%
rename from identity-apps-core/apps/authentication-portal/src/main/webapp/util/create-account-api.jsp
rename to identity-apps-core/apps/authentication-portal/src/main/webapp/util/self-registration-api.jsp
index 4b917ee9743..c9a1097cb05 100644
--- a/identity-apps-core/apps/authentication-portal/src/main/webapp/util/create-account-api.jsp
+++ b/identity-apps-core/apps/authentication-portal/src/main/webapp/util/self-registration-api.jsp
@@ -21,20 +21,26 @@
<%
StringBuilder requestBody = new StringBuilder();
String line;
- boolean useCreatedObject = false;
+ boolean isSubmitRequest = false;
+ String endpoint = "";
- // Read the request body
try (BufferedReader reader = request.getReader()) {
while ((line = reader.readLine()) != null) {
requestBody.append(line);
}
- // Check if the request does NOT contain "applicationId"
+ System.out.println("Request: " + requestBody.toString());
+
if (requestBody.length() > 0) {
- System.out.print(requestBody);
JSONObject requestJson = new JSONObject(requestBody.toString());
- if (!requestJson.has("applicationId")) {
- useCreatedObject = true; // Flag to use the "created" object
+ if (requestJson.has("applicationId")) {
+ endpoint = "/data/init-response.json";
+ } else if (requestJson.has("action") && "PasswordOnboarder".equalsIgnoreCase(requestJson.getString("action"))) {
+ endpoint = "/data/password-submit-response.json";
+ } else if (requestJson.has("action") && "EmailOTPVerifier1".equalsIgnoreCase(requestJson.getString("action"))) {
+ endpoint = "/data/emailotp-submit-1-response.json";
+ } else if (requestJson.has("action") && "EmailOTPVerifier2".equalsIgnoreCase(requestJson.getString("action"))) {
+ endpoint = "/data/emailotp-submit-2-response.json";
}
}
} catch (Exception e) {
@@ -47,18 +53,26 @@
int serverPort = request.getServerPort();
String contextPath = request.getContextPath();
- // Construct the API URL
- String apiUrl = scheme + "://" + serverName + ":" + serverPort + contextPath + "/registration-mock-data.json";
+ String apiURL = scheme + "://" + serverName + ":" + serverPort + contextPath + endpoint;
StringBuilder apiResponse = new StringBuilder();
HttpURLConnection connection = null;
try {
- URL url = new URL(apiUrl);
+ URL url = new URL(apiURL);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/json");
+ connection.setDoOutput(true);
+
+ // if (requestBody.length() > 0) {
+ // try (OutputStream os = connection.getOutputStream()) {
+ // byte[] input = requestBody.toString().getBytes("utf-8");
+ // os.write(input, 0, input.length);
+ // }
+ // }
+
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
@@ -70,18 +84,9 @@
in.close();
// Parse the API response JSON
- JSONObject apiJson = new JSONObject(apiResponse.toString());
+ JSONObject responseObject = new JSONObject(apiResponse.toString());
- // Select the appropriate object based on the request content
- JSONObject responseObject;
-
- if (useCreatedObject && apiJson.has("created")) {
- responseObject = apiJson.getJSONObject("created");
- } else if (apiJson.has("init")) {
- responseObject = apiJson.getJSONObject("init");
- } else {
- responseObject = new JSONObject().put("error", "Invalid API response");
- }
+ System.out.println("Response: " + responseObject.toString(2));
// Send the selected object as the response
out.print(responseObject.toString(2));
diff --git a/identity-apps-core/features/org.wso2.identity.apps.authentication.portal.server.feature/resources/web.xml.j2 b/identity-apps-core/features/org.wso2.identity.apps.authentication.portal.server.feature/resources/web.xml.j2
index efd29750b39..1cf780e0eaa 100644
--- a/identity-apps-core/features/org.wso2.identity.apps.authentication.portal.server.feature/resources/web.xml.j2
+++ b/identity-apps-core/features/org.wso2.identity.apps.authentication.portal.server.feature/resources/web.xml.j2
@@ -343,7 +343,8 @@
{"name": "magic_link_notification.do", "jsp": "/magic_link_notification.jsp", "url": "/magic_link_notification.do"},
{"name": "org_name.do", "jsp": "/org_name.jsp", "url": "/org_name.do"},
{"name": "org_discovery.do", "jsp": "/org_discovery.jsp", "url": "/org_discovery.do"},
- {"name": "select_org.do", "jsp": "/select_org.jsp", "url": "/select_org.do"}
+ {"name": "select_org.do", "jsp": "/select_org.jsp", "url": "/select_org.do"},
+ { "name": "register.do", "jsp": "/create-account.jsp", "url": "/register.do"},
] %}
{% for servlet_item in default_servlets %}
{% set key_name = servlet_item['name'] %}
diff --git a/identity-apps-core/react-ui-core/src/components/adapters/button-field-adapter.js b/identity-apps-core/react-ui-core/src/components/adapters/button-field-adapter.js
new file mode 100644
index 00000000000..ca2e6a480be
--- /dev/null
+++ b/identity-apps-core/react-ui-core/src/components/adapters/button-field-adapter.js
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import classNames from "classnames";
+import PropTypes from "prop-types";
+import React from "react";
+import { useTranslations } from "../../hooks/use-translations";
+import { getTranslationByKey } from "../../utils/i18n-utils";
+
+const ButtonAdapter = ({ component, handleButtonAction }) => {
+
+ const { translations } = useTranslations();
+
+ switch (component.variant) {
+ case "PRIMARY":
+ return (
+
+
+ { getTranslationByKey(translations, component.properties.text) }
+
+
+ );
+ case "SECONDARY":
+ return (
+
+
+ { getTranslationByKey(translations, component.properties.text) }
+
+
+ );
+ case "LINK":
+ return (
+
+
+ { getTranslationByKey(translations, component.properties.text) }
+
+
+ );
+ case "SOCIAL_BUTTON":
+ return (
+
+
+ { getTranslationByKey(translations, component.properties.text) }
+
+
+ );
+ default:
+ return (
+
+
+ { getTranslationByKey(translations, component.properties.text) }
+
+
+ );
+ }
+};
+
+ButtonAdapter.propTypes = {
+ actionHandler: PropTypes.func.isRequired,
+ component: PropTypes.shape({
+ properties: PropTypes.shape({
+ className: PropTypes.string,
+ styles: PropTypes.object,
+ text: PropTypes.string.isRequired
+ }).isRequired,
+ type: PropTypes.string,
+ variant: PropTypes.string
+ }).isRequired
+};
+
+export default ButtonAdapter;
diff --git a/identity-apps-core/react-ui-core/src/components/adapters/country-field-adapter.js b/identity-apps-core/react-ui-core/src/components/adapters/country-field-adapter.js
new file mode 100644
index 00000000000..bdcb32a1789
--- /dev/null
+++ b/identity-apps-core/react-ui-core/src/components/adapters/country-field-adapter.js
@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import classNames from "classnames";
+import React, { useEffect, useState } from "react";
+
+const CountryFieldAdapter = ({ component, formStateHandler }) => {
+
+ const { required, name, rest } = component.properties;
+
+ const [ countryList, setCountryList ] = useState([]);
+
+ useEffect(() => {
+ const countryList = getCountryList();
+
+ setCountryList(countryList);
+ }, []);
+
+ const getCountryList = () => {
+ const countryCodes = Intl.supportedValuesOf("region");
+ const countryMap = {};
+
+ countryCodes.forEach((countryCode) => {
+ const locale = new Intl.DisplayNames([ "en" ], { type: "region" });
+ const countryDisplayName = locale.of(countryCode);
+
+ countryMap[countryCode] = countryDisplayName;
+ });
+
+ return countryMap;
+ };
+
+ return (
+
+
+
+
+
Enter Country
+
+ {
+ countryList && Object.keys(countryList).map((countryCode, index) => {
+ return (
+
{
+ formStateHandler(
+ name, e.target.getAttribute("data-value")
+ );
+ } }
+ >
+
+ { countryList[ countryCode ] }
+
+ );
+ })
+ }
+
+
+
+ );
+};
+
+export default CountryFieldAdapter;
diff --git a/identity-apps-core/react-ui-core/src/components/adapters/input-field-adapter.js b/identity-apps-core/react-ui-core/src/components/adapters/input-field-adapter.js
new file mode 100644
index 00000000000..dbade3048cb
--- /dev/null
+++ b/identity-apps-core/react-ui-core/src/components/adapters/input-field-adapter.js
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import PropTypes from "prop-types";
+import React from "react";
+import CountryFieldAdapter from "./country-field-adapter";
+import OTPFieldAdapter from "./otp-field-adapter";
+import PasswordFieldAdapter from "./password-field-adapter";
+import TextFieldAdapter from "./text-field-adapter";
+
+const InputFieldAdapter = ({ component, formStateHandler, formErrorHandler }) => {
+
+ switch (component.variant) {
+ case "TEXT":
+ return (
+
+ );
+ case "DATE":
+ return
;
+ case "PASSWORD":
+ return (
+
+ );
+ case "OTP":
+ return (
+
+ );
+ default:
+ return null;
+ }
+};
+
+InputFieldAdapter.propTypes = {
+ component: PropTypes.object.isRequired,
+ formState: PropTypes.object.isRequired,
+ formStateHandler: PropTypes.func.isRequired
+};
+
+export default InputFieldAdapter;
diff --git a/identity-apps-core/react-ui-core/src/components/adapters/otp-field-adapter.js b/identity-apps-core/react-ui-core/src/components/adapters/otp-field-adapter.js
new file mode 100644
index 00000000000..862c1da7d09
--- /dev/null
+++ b/identity-apps-core/react-ui-core/src/components/adapters/otp-field-adapter.js
@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import classNames from "classnames";
+import PropTypes from "prop-types";
+import React, { useEffect, useState } from "react";
+import { useTranslations } from "../../hooks/use-translations";
+import { getTranslationByKey } from "../../utils/i18n-utils";
+
+const OTPFieldAdapter = ({ component, formStateHandler, otpLength = 6 }) => {
+
+ const { label, required, styles } = component.properties;
+
+ const { translations } = useTranslations();
+
+ const [ otpValues, setOtpValues ] = useState(Array(otpLength).fill(""));
+
+ useEffect(() => {
+ formStateHandler(component.properties.name, otpValues.join(""));
+ }, [ otpValues ]);
+
+ const movetoNext = (current, nextFieldID, previousID) => {
+
+ const key = event.keyCode || event.charCode;
+
+ if (key == 8 || key == 46) {
+ if (previousID != null && previousID != "null") {
+ document.getElementById(previousID).focus();
+ }
+ } else {
+ if (nextFieldID != null && nextFieldID != "null" && current.value.length >= current.maxLength) {
+ document.getElementById(nextFieldID).focus();
+ }
+ }
+ };
+
+ return (
+
+
{ getTranslationByKey(translations, label) }
+ { otpLength <= 6 ? (
+
+ ) : (
+
+ setOtpValues(e.target.value.split("").slice(0, otpLength)) }
+ data-testid="recovery-otp-page-non-segmented-otp-input"
+ />
+ {
+ const otpField = document.getElementById("OTPCode");
+
+ if (otpField.type === "text") {
+ otpField.type = "password";
+ document.getElementById("password-eye").classList.remove("slash");
+ } else {
+ otpField.type = "text";
+ document.getElementById("password-eye").classList.add("slash");
+ }
+ } }
+ />
+
+ ) }
+
+ );
+};
+
+OTPFieldAdapter.propTypes = {
+ component: PropTypes.shape({
+ properties: PropTypes.shape({
+ label: PropTypes.string,
+ name: PropTypes.string,
+ placeholder: PropTypes.string,
+ value: PropTypes.string
+ }).isRequired
+ }).isRequired,
+ formStateHandler: PropTypes.func.isRequired,
+ otpLength: PropTypes.number
+};
+
+export default OTPFieldAdapter;
diff --git a/identity-apps-core/react-ui-core/src/components/adapters/password-field-adapter.js b/identity-apps-core/react-ui-core/src/components/adapters/password-field-adapter.js
new file mode 100644
index 00000000000..cca700207b7
--- /dev/null
+++ b/identity-apps-core/react-ui-core/src/components/adapters/password-field-adapter.js
@@ -0,0 +1,109 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import classNames from "classnames";
+import PropTypes from "prop-types";
+import React, { useEffect, useState } from "react";
+import useFieldValidation from "../../hooks/use-field-validations";
+import { useTranslations } from "../../hooks/use-translations";
+import { getTranslationByKey } from "../../utils/i18n-utils";
+import ValidationCriteria from "../field-validation";
+
+const PasswordFieldAdapter = ({ component, formStateHandler, formErrorHandler }) => {
+
+ const { required, name, label, placeholder, rest, validation } = component.properties;
+
+ const { translations } = useTranslations();
+ const { fieldErrors, validate } = useFieldValidation(validation);
+
+ const [ password, setPassword ] = useState("");
+ const [ showPassword, setShowPassword ] = useState(false);
+
+ useEffect(() => {
+ formStateHandler(name, password);
+ }, [ password ]);
+
+ const handleFieldValidation = (value) => {
+ if (validation) {
+ validate(value);
+ formErrorHandler(component.properties.name, fieldErrors);
+ }
+ };
+
+ return (
+
+
{ getTranslationByKey(translations, label) }
+
+ setPassword(e.target.value) }
+ onBlur={ (e) => handleFieldValidation(e.target.value) }
+ { ...rest }
+ />
+
+ setShowPassword(!showPassword) }
+ />
+
+ { validation && (
+
+ ) }
+
+
+ );
+};
+
+PasswordFieldAdapter.propTypes = {
+ component: PropTypes.shape({
+ properties: PropTypes.shape({
+ label: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ placeholder: PropTypes.string.isRequired,
+ value: PropTypes.string,
+ policies: PropTypes.arrayOf(
+ PropTypes.shape({
+ description: PropTypes.string.isRequired,
+ key: PropTypes.string.isRequired,
+ policy: PropTypes.string.isRequired,
+ value: PropTypes.oneOfType([ PropTypes.string, PropTypes.number ]).isRequired
+ })
+ ).isRequired,
+ policyCriteria: PropTypes.arrayOf(
+ PropTypes.shape({
+ appliesTo: PropTypes.arrayOf(PropTypes.string).isRequired,
+ criteria: PropTypes.string.isRequired,
+ description: PropTypes.string.isRequired
+ })
+ ).isRequired,
+ showValidationCriteria: PropTypes.bool
+ }).isRequired
+ }).isRequired,
+ formStateHandler: PropTypes.func.isRequired
+};
+
+export default PasswordFieldAdapter;
diff --git a/identity-apps-core/react-ui-core/src/components/adapters/text-field-adapter.js b/identity-apps-core/react-ui-core/src/components/adapters/text-field-adapter.js
new file mode 100644
index 00000000000..ecadc30bf65
--- /dev/null
+++ b/identity-apps-core/react-ui-core/src/components/adapters/text-field-adapter.js
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import classNames from "classnames";
+import PropTypes from "prop-types";
+import React, { useEffect, useState } from "react";
+import useFieldValidation from "../../hooks/use-field-validations";
+import { useTranslations } from "../../hooks/use-translations";
+import { getTranslationByKey } from "../../utils/i18n-utils";
+import { getInputIconClass } from "../../utils/ui-utils";
+import ValidationCriteria from "../field-validation";
+
+const TextFieldAdapter = ({ component, formStateHandler, formErrorHandler }) => {
+
+ const { name, required, styles, label, placeholder, rest, validation } = component.properties;
+
+ const { translations } = useTranslations();
+ const { fieldErrors, validate } = useFieldValidation(validation);
+
+ const [ value, setValue ] = useState("");
+
+ useEffect(() => {
+ formStateHandler(component.properties.name, value);
+ }, [ value ]);
+
+ const handleFieldValidation = (value) => {
+ if (validation) {
+ validate(value);
+ formErrorHandler(component.properties.name, fieldErrors);
+ }
+ };
+
+ const inputIconClass = getInputIconClass(name);
+
+ return (
+
+
{ getTranslationByKey(translations, label) }
+
+ setValue(e.target.value) }
+ onBlur={ (e) => handleFieldValidation(e.target.value) }
+ required={ required }
+ { ...rest }
+ />
+ {
+ inputIconClass
+ ?
+ : null
+ }
+
+ { validation && (
+
+ ) }
+
+ );
+};
+
+TextFieldAdapter.propTypes = {
+ component: PropTypes.object.isRequired,
+ formStateHandler: PropTypes.func.isRequired
+};
+
+export default TextFieldAdapter;
diff --git a/identity-apps-core/react-ui-core/src/components/adapters/typography-field-adapter.js b/identity-apps-core/react-ui-core/src/components/adapters/typography-field-adapter.js
new file mode 100644
index 00000000000..f0e4a347c28
--- /dev/null
+++ b/identity-apps-core/react-ui-core/src/components/adapters/typography-field-adapter.js
@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import PropTypes from "prop-types";
+import React from "react";
+import { useTranslations } from "../../hooks/use-translations";
+import { getTranslationByKey } from "../../utils/i18n-utils";
+
+const TypographyAdapter = ({ component }) => {
+ const { variant, properties } = component;
+ const { className, styles, text } = properties;
+
+ const { translations } = useTranslations ();
+
+ switch (variant) {
+ case "H3":
+ return (
+
+ { getTranslationByKey(translations, text) }
+
+ );
+ case "H1":
+ return
{ text } ;
+ case "H2":
+ return
{ text } ;
+ default:
+ return
{ text }
;
+ }
+};
+
+TypographyAdapter.propTypes = {
+ id: PropTypes.string,
+ category: PropTypes.string,
+ type: PropTypes.string,
+ properties: PropTypes.shape({
+ text: PropTypes.string.isRequired,
+ className: PropTypes.string,
+ styles: PropTypes.object
+ }).isRequired,
+ variant: PropTypes.string.isRequired
+};
+
+export default TypographyAdapter;
diff --git a/identity-apps-core/react-ui-core/src/components/display-field.js b/identity-apps-core/react-ui-core/src/components/display-field.js
new file mode 100644
index 00000000000..82ffc65aca5
--- /dev/null
+++ b/identity-apps-core/react-ui-core/src/components/display-field.js
@@ -0,0 +1,34 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import React from "react";
+import TypographyAdapter from "./adapters/typography-field-adapter";
+import DividerAdapter from "./divider";
+
+const DisplayField = (component) => {
+ switch (component.type) {
+ case "TYPOGRAPHY":
+ return
;
+ case "DIVIDER":
+ return
;
+ default:
+ return null;
+ }
+};
+
+export default DisplayField;
diff --git a/identity-apps-core/react-ui-core/src/components/divider.js b/identity-apps-core/react-ui-core/src/components/divider.js
new file mode 100644
index 00000000000..4e81af5e47d
--- /dev/null
+++ b/identity-apps-core/react-ui-core/src/components/divider.js
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import PropTypes from "prop-types";
+import React, { useEffect, useState } from "react";
+
+
+const DividerAdapter = ({ component }) => {
+
+ const [ element, setElement ] = useState({});
+
+ useEffect(() => {
+
+ if (!component) {
+
+ return;
+ }
+
+ setElement(component);
+ }, [ component ]);
+
+ if (element.variant === "HORIZONTAL") {
+ return (
+
+ { element.properties.text && { element.properties.text } }
+
+ );
+ }
+
+ return null;
+};
+
+DividerAdapter.propTypes = {
+ component: PropTypes.object.isRequired
+};
+
+export default DividerAdapter;
diff --git a/identity-apps-core/react-ui-core/src/components/dynamic-content.js b/identity-apps-core/react-ui-core/src/components/dynamic-content.js
new file mode 100644
index 00000000000..39788cb0f34
--- /dev/null
+++ b/identity-apps-core/react-ui-core/src/components/dynamic-content.js
@@ -0,0 +1,110 @@
+/**
+ * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import PropTypes from "prop-types";
+import React from "react";
+import ButtonFieldAdapter from "./adapters/button-field-adapter";
+import Field from "./field";
+import Form from "./form";
+
+const DynamicContent = ({ content, handleRequestBody }) => {
+ const renderedElementIds = new Set();
+
+ const renderBlock = (block) => {
+ if (!block) return null;
+
+ const blockElements = block.nodes
+ .map((nodeId) => {
+ const element = content.elements.find((el) => el.id === nodeId);
+
+ if (element && !renderedElementIds.has(element.id)) {
+ renderedElementIds.add(element.id);
+
+ return element;
+ }
+
+ return null;
+ })
+ .filter(Boolean);
+
+ if (blockElements.length > 0) {
+ return (
+