diff --git a/identity-apps-core/apps/authentication-portal/src/main/webapp/WEB-INF/web.xml b/identity-apps-core/apps/authentication-portal/src/main/webapp/WEB-INF/web.xml index cdc24cb7018..f7ae39d2d31 100644 --- a/identity-apps-core/apps/authentication-portal/src/main/webapp/WEB-INF/web.xml +++ b/identity-apps-core/apps/authentication-portal/src/main/webapp/WEB-INF/web.xml @@ -387,6 +387,11 @@ /select_org.jsp + + register.do + /self-registration.jsp + + totp_enroll.do /totp_enroll.do @@ -607,6 +612,11 @@ /duo_error.do + + register.do + /register.do + + java.lang.Throwable /generic-exception-response.jsp diff --git a/identity-apps-core/apps/authentication-portal/src/main/webapp/create-account.jsp b/identity-apps-core/apps/authentication-portal/src/main/webapp/create-account.jsp deleted file mode 100644 index fe2583d419e..00000000000 --- a/identity-apps-core/apps/authentication-portal/src/main/webapp/create-account.jsp +++ /dev/null @@ -1,191 +0,0 @@ -<%-- - ~ 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" %> -<%@ 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"); -%> - - - - - <%-- 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/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 ( +
+ +
+ ); + case "SECONDARY": + return ( +
+ +
+ ); + case "LINK": + return ( +
+ +
+ ); + case "SOCIAL_BUTTON": + return ( +
+ +
+ ); + default: + return ( +
+ +
+ ); + } +}; + +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 ( +
+ + { otpLength <= 6 ? ( +
+ + { otpValues.map((index) => { + + let previousStringIndex = null; + let nextStringIndex = null; + + if (index != 1) { + previousStringIndex = "pincode-" + (index - 1); + } + + index++; + + if (index != (otpLength + 1)) { + nextStringIndex = "pincode-" + index; + } + + return ( +
+ movetoNext(this, nextStringIndex, previousStringIndex) } + tabIndex="1" + placeholder="·" + autoFocus + maxLength="1" + /> +
+ ); + }) } +
+ ) : ( +
+ 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 ( +
+ +
+ 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 ( +
+ +
+ 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 ( +
handleRequestBody(action, formValues) } + /> + ); + } + + return null; + }; + + // Render all elements + const renderElements = () => { + return content.elements.map((element, index) => { + // Render DISPLAY elements + if (element.category === "DISPLAY" && !renderedElementIds.has(element.id)) { + renderedElementIds.add(element.id); + + return ; + } + + // Render BLOCK elements + const block = content.blocks.find((blk) => blk.nodes.includes(element.id)); + + if (block && !renderedElementIds.has(element.id)) { + return renderBlock(block); + } + + // Render ACTION elements that are not bound to any block + if ( + element.category === "ACTION" && + !renderedElementIds.has(element.id) + ) { + renderedElementIds.add(element.id); + + if (!element) { + return null; + } + + return ( + + ); + } + + return null; + }); + }; + + return <>{ renderElements() }; +}; + +DynamicContent.propTypes = { + content: PropTypes.shape({ + blocks: PropTypes.array.isRequired, + elements: PropTypes.array.isRequired + }).isRequired, + handleRequestBody: PropTypes.func.isRequired +}; + +export default DynamicContent; diff --git a/identity-apps-core/react-ui-core/src/components/field-validation.js b/identity-apps-core/react-ui-core/src/components/field-validation.js new file mode 100644 index 00000000000..dffd940da71 --- /dev/null +++ b/identity-apps-core/react-ui-core/src/components/field-validation.js @@ -0,0 +1,102 @@ +/** + * 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"; + +/** + * ValidationCriteria Component + * + * @param {Object} props - The component props. + * @param {Object} props.validationConfig - The validation configuration object. + * @param {string} props.value - The value to validate. + */ +const ValidationCriteria = ({ validationConfig, errors, value }) => { + + const { translations } = useTranslations(); + + const PolicyValidationStatus = ({ isValid }) => { + return ( +
+ { + value.length === 0 + ? ( + + ) : ( + <> + { + isValid + ? ( + + ) + : ( + + ) + } + + ) + + } +
+ ); + }; + + return ( +
+ { + validationConfig && + validationConfig.map((validation, index) => { + if (validation.type === "CRITERIA" && validation.showValidationCriteria) { + return validation.criteria.map((criterion, criteriaIndex) => { + const hasError = errors.some( + (error) => error.label === criterion.label + ); + + return ( +
+
+ +

+ { getTranslationByKey(translations, criterion.label) } +

+
+
+ ); + }); + } else { + return ( +
+ + { errors[ errors.length - 1 ].error } +
+ ); + } + }) + } +
+ ); +}; + +ValidationCriteria.propTypes = { + validationConfig: PropTypes.object.isRequired, + value: PropTypes.string.isRequired +}; + +export default ValidationCriteria; diff --git a/identity-apps-core/react-ui-core/src/components/field.js b/identity-apps-core/react-ui-core/src/components/field.js new file mode 100644 index 00000000000..51fb01f826b --- /dev/null +++ b/identity-apps-core/react-ui-core/src/components/field.js @@ -0,0 +1,48 @@ +/** + * 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 ButtonFieldAdapter from "./adapters/button-field-adapter"; +import InputFieldAdapter from "./adapters/input-field-adapter"; +import TypographyAdapter from "./adapters/typography-field-adapter"; +import DividerAdapter from "./divider"; + +const Field = ({ component, formStateHandler, formErrorHandler }) => { + + switch (component.type) { + case "TYPOGRAPHY": + return ; + case "INPUT": + return ( + + ); + case "BUTTON": + return ; + case "DIVIDER": + return ; + default: + return null; + } +}; + +export default Field; diff --git a/identity-apps-core/react-ui-core/src/components/form.js b/identity-apps-core/react-ui-core/src/components/form.js new file mode 100644 index 00000000000..757f315206e --- /dev/null +++ b/identity-apps-core/react-ui-core/src/components/form.js @@ -0,0 +1,48 @@ +/** + * 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 Field from "./field"; +import useDynamicForm from "../hooks/use-dynamic-form"; + +const Form = ({ formSchema, onSubmit }) => { + const { + handleChange, + handleSubmit, + handleFormErrors + } = useDynamicForm(formSchema); + + return ( +
+ + { + formSchema.map((field, index) => ( + + )) + } + +
+ ); +}; + +export default Form; diff --git a/identity-apps-core/react-ui-core/src/hooks/use-dynamic-form.js b/identity-apps-core/react-ui-core/src/hooks/use-dynamic-form.js new file mode 100644 index 00000000000..e3febd40b2e --- /dev/null +++ b/identity-apps-core/react-ui-core/src/hooks/use-dynamic-form.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 { useCallback, useEffect, useState } from "react"; + +const useDynamicForm = (fields) => { + + const [ formState, setFormState ] = useState({ + dirtyFields: {}, + disabled: false, + errors: {}, + isDirty: false, + isLoading: false, + isValidating: false, + isSubmitted: false, + isSubmitting: false, + isSubmitSuccessful: false, + isValid: false, + touchedFields: {}, + values: {} + }); + const [ formErrors, setFormErrors ] = useState({}); + + useEffect(() => { + if (!formErrors) { + return; + } + + setFormState((prev) => ({ + ...prev, + errors: formErrors, + isValid: !formErrors || Object.keys(formErrors).length === 0 + })); + }, [ formErrors ]); + + // Handle changes in form fields + const handleChange = useCallback((name, value) => { + setFormState((prev) => { + const updatedValues = { + ...prev.values, + [name]: value + }; + + return { + ...prev, + values: updatedValues, + touched: { + ...prev.touched, + [name]: true + }, + isDirty: true + }; + }); + }, [ fields ]); + + const handleSubmit = useCallback((onSubmit) => (event) => { + + event.preventDefault(); + + setFormState((prev) => ({ ...prev, isSubmitting: true })); + + let hasErrors = false; + const newErrors = {}; + + fields.forEach((field) => { + + const fieldErrors = formState.errors[field.properties.name]; + + if (fieldErrors && fieldErrors.length > 0) { + hasErrors = true; + newErrors[field.properties.name] = fieldErrors; + } + }); + + setFormState((prev) => ({ + ...prev, + errors: newErrors, + isSubmitting: false + })); + + if (!hasErrors) { + onSubmit(event.nativeEvent.submitter.name, formState.values); + } + }, [ fields, formState.values ]); + + return { + formState, + handleChange, + handleFormErrors: setFormErrors, + handleSubmit + }; +}; + +export default useDynamicForm; diff --git a/identity-apps-core/react-ui-core/src/hooks/use-field-validations.js b/identity-apps-core/react-ui-core/src/hooks/use-field-validations.js new file mode 100644 index 00000000000..97c3a5be806 --- /dev/null +++ b/identity-apps-core/react-ui-core/src/hooks/use-field-validations.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 { useCallback, useState } from "react"; + +const useFieldValidation = (validationConfig) => { + + const [ fieldErrors, setFieldErrors ] = useState([]); + + const validateCriterion = useCallback((criterion, value) => { + switch (criterion.type) { + case "REQUIRED": + if (!value) { + return criterion.error || "This field is required."; + } + + break; + + case "MIN_LENGTH": + if (value.length < criterion.value) { + return criterion.error || `Must be at least ${criterion.value} characters long.`; + } + + break; + + case "MAX_LENGTH": + if (value.length > criterion.value) { + return criterion.error || `Must be at most ${criterion.value} characters long.`; + } + + break; + + case "PATTERN": + if (!new RegExp(criterion.value).test(value)) { + return criterion.error || "Invalid pattern."; + } + + break; + + case "MIN_NUMBERS": + if ((value.match(/[0-9]/g) || []).length < criterion.value) { + return criterion.error || `Must contain at least ${criterion.value} number(s).`; + } + + break; + + case "MIN_UPPERCASE_LETTERS": + if ((value.match(/[A-Z]/g) || []).length < criterion.value) { + return criterion.error || `Must contain at least ${criterion.value} uppercase letter(s).`; + } + + break; + + case "MIN_LOWERCASE_LETTERS": + if ((value.match(/[a-z]/g) || []).length < criterion.value) { + return criterion.error || `Must contain at least ${criterion.value} lowercase letter(s).`; + } + + break; + + case "MIN_SPECIAL_CHARACTERS": + if ((value.match(/[^a-zA-Z0-9]/g) || []).length < criterion.value) { + return criterion.error || `Must contain at least ${criterion.value} special character(s).`; + } + + break; + + case "MAX_REPEATED_CHARACTERS": + { + const repeatedChars = value.split("").filter((char, i, arr) => arr.indexOf(char) !== i); + + if (repeatedChars.length > criterion.value) { + return criterion.error || "Must not contain repeated characters."; + } + } + + break; + + default: + break; + } + + return null; + }, []); + + const validate = useCallback((value) => { + let validationErrors = []; + + if (validationConfig) { + for (const validation of validationConfig) { + if (validation.type === "CRITERIA" && validation.criteria) { + for (const criterion of validation.criteria) { + + for (const validation of criterion.validation) { + const error = validateCriterion(validation, value); + + if (error) { + validationErrors.push({ + label: criterion.label, + error + }); + } + } + } + } else { + const error = validateCriterion(validation, value); + + if (error) { + validationErrors.push({ + label: validation.label, + error + }); + } + } + } + } + + setFieldErrors(validationErrors); + + return validationErrors.length === 0; + }, [ validationConfig, validateCriterion ]); + + return { fieldErrors, validate }; +}; + +export default useFieldValidation; diff --git a/identity-apps-core/ui-components/Form.js b/identity-apps-core/react-ui-core/src/hooks/use-translations.js similarity index 55% rename from identity-apps-core/ui-components/Form.js rename to identity-apps-core/react-ui-core/src/hooks/use-translations.js index 82ee795c8e6..87e8d3455e2 100644 --- a/identity-apps-core/ui-components/Form.js +++ b/identity-apps-core/react-ui-core/src/hooks/use-translations.js @@ -1,29 +1,28 @@ -/* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). +/** + * 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 + * 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 + * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ -import { useState } from 'react'; +import { useContext } from "react"; +import { I18nContext } from "../providers/i18n-provider"; -const Form = ({ children }) => { - const [state, setState] = useState(null); +/** + * Custom hook to use i18n in components. + */ +export const useTranslations = () => { - return ( - { children } - ); + return useContext(I18nContext); }; - -export default Form; diff --git a/identity-apps-core/react-ui-core/src/index.js b/identity-apps-core/react-ui-core/src/index.js new file mode 100644 index 00000000000..90a09109843 --- /dev/null +++ b/identity-apps-core/react-ui-core/src/index.js @@ -0,0 +1,35 @@ +/** + * 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. + */ + +export { default as ButtonFieldAdapter } from "./components/adapters/button-field-adapter"; +export { default as TypographyFieldAdapter } from "./components/adapters/typography-field-adapter"; +export { default as InputFieldAdapter } from "./components/adapters/input-field-adapter"; +export { default as Divider } from "./components/divider"; +export { default as Form } from "./components/form"; +export { default as ValidationCriteria } from "./components/field-validation"; +export { default as Field } from "./components/field"; +export { default as DynamicContent } from "./components/dynamic-content"; + +export * from "./hooks/use-field-validations"; +export * from "./hooks/use-translations"; + +export { I18nProvider } from "./providers/i18n-provider"; + +export * from "./utils/i18n-utils"; +export * from "./utils/ui-utils"; +export * from "./utils/validation-utils"; diff --git a/identity-apps-core/react-ui-core/src/providers/i18n-provider.js b/identity-apps-core/react-ui-core/src/providers/i18n-provider.js new file mode 100644 index 00000000000..d62185ab89b --- /dev/null +++ b/identity-apps-core/react-ui-core/src/providers/i18n-provider.js @@ -0,0 +1,46 @@ +/** + * 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, { createContext, useEffect, useState } from "react"; + +export const I18nContext = createContext(); + +export const I18nProvider = ({ locale, translationsObject, children }) => { + + const [ translations, setTranslations ] = useState({}); + + useEffect(() => { + const loadTranslations = async () => { + try { + + setTranslations(translationsObject); + } catch (err) { + console.error("Error loading translations:", err); + } + }; + + loadTranslations(); + }, []); + + return ( + + { children } + + ); +}; + diff --git a/identity-apps-core/react-ui-core/src/utils/i18n-utils.js b/identity-apps-core/react-ui-core/src/utils/i18n-utils.js new file mode 100644 index 00000000000..41779a7a8a0 --- /dev/null +++ b/identity-apps-core/react-ui-core/src/utils/i18n-utils.js @@ -0,0 +1,54 @@ +/** + * 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. + */ + +/** + * Dynamically imports the appropriate translations object for a given locale. + * @param {string} locale - The locale code (e.g., 'en', 'fr', 'es'). + * @returns {Promise} - A promise that resolves to the translations object for the given locale. + */ +export const getLocaleTranslations = async (basePath, locale = "en-US") => { + try { + const translations = await require(`${basePath}/i18n/translations/${locale}.json`); + + return translations; + } catch (error) { + console.error(`Error loading locale ${locale}:`, error); + } +}; + +/** + * Safely accesses a translation value using a flat key. + * @param {Object} translations - The translations object. + * @param {string} key - The key (e.g., 'form.fields.password'). + * @returns {string} - The translation value. + */ +export const getTranslationByKey = (translations, key) => { + + return translations[key]; +}; + +/** + * Converts the translations object into a Map. + * @param {string} locale - The locale code (e.g., 'en', 'fr', 'es'). + * @returns {Promise} - A promise that resolves to a Map of the translations for the given locale. + */ +export const getLocaleTranslationMap = async (basePath, locale = "en-US") => { + const translationObject = await getLocaleTranslations(basePath, locale); + + return new Map(Object.entries(translationObject)); +}; diff --git a/identity-apps-core/react-ui-core/src/utils/ui-utils.js b/identity-apps-core/react-ui-core/src/utils/ui-utils.js new file mode 100644 index 00000000000..298403293cf --- /dev/null +++ b/identity-apps-core/react-ui-core/src/utils/ui-utils.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. + */ + +/** + * Returns the appropriate icon class for a given field. + * @param {string} fieldName - The name or type of the field (e.g., "email", "username"). + * @returns {string|null} - The icon class to be used or null if no icon should be shown. + */ +export const getInputIconClass = (fieldName) => { + const iconMapping = { + address: "home", + email: "envelope outline", + password: "lock", + phone: "phone", + username: "user outline" + }; + + return iconMapping[fieldName] || null; +}; diff --git a/identity-apps-core/ui-components/PageHead.js b/identity-apps-core/react-ui-core/src/utils/validation-utils.js similarity index 54% rename from identity-apps-core/ui-components/PageHead.js rename to identity-apps-core/react-ui-core/src/utils/validation-utils.js index 87c91cd464a..5c4b33df327 100644 --- a/identity-apps-core/ui-components/PageHead.js +++ b/identity-apps-core/react-ui-core/src/utils/validation-utils.js @@ -1,23 +1,28 @@ -/* - * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). +/** + * 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 + * 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 + * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ -const PageHead = ({ component }) => { - return

{ component.properties.heading }

; -}; +export const isRequired = value => value !== undefined && value !== null && value.trim() !== ""; + +export const validateEmail = (email, emailRegex) => { + if (!email) { -export default PageHead; + return false; + } + + return emailRegex.test(email); +}; diff --git a/identity-apps-core/static-files-distribute.js b/identity-apps-core/static-files-distribute.js index 7445bacaf6e..1b041ed1e60 100644 --- a/identity-apps-core/static-files-distribute.js +++ b/identity-apps-core/static-files-distribute.js @@ -22,7 +22,7 @@ const fs = require("fs-extra"); const themeFiles = path.join(__dirname, "..", "modules", "theme", "dist", "lib"); const apps = [ "authentication-portal", "recovery-portal", "x509-certificate-authentication-portal" ]; -const ReactComponentsJSFile = "react-ui-components.min.js"; +const ReactComponentsJSFile = "react-ui-core.min.js"; const appReactComponentsJSFilePath = path.join(__dirname, "apps", `${apps[0]}`, "src", "main", "webapp", "js"); const transpiledReactComponentsJSFilePath = path.join(__dirname, "dist"); @@ -45,21 +45,21 @@ async function copyThemeFiles() { } } -// Check for the react-ui-components file and delete it if exists. +// Check for the react-ui-core module and delete it if exists. async function deleteExistingAppReactComponentsJSFile() { if (fs.existsSync(path.join(appReactComponentsJSFilePath, ReactComponentsJSFile))) { - console.log(`Deleting existing react-ui-components file in ${apps[0]} app...`); + console.log(`Deleting existing react-ui-core module in ${apps[0]} app...`); await fs.remove(path.join(appReactComponentsJSFilePath, ReactComponentsJSFile)); } } -// Copy the react-ui-components.js file to authentication app. +// Copy the react-ui-core.js file to authentication portal. async function copyAppReactComponentsJSFile() { - console.log(`Copying react-ui-components file to ${apps[0]} app...`); + console.log(`Copying react-ui-core file to ${apps[0]} app...`); await fs.copyFile( path.join(transpiledReactComponentsJSFilePath, ReactComponentsJSFile), - path.join(appReactComponentsJSFilePath, ReactComponentsJSFile) - ); + path.join(appReactComponentsJSFilePath, ReactComponentsJSFile) + ); } async function main() { diff --git a/identity-apps-core/ui-components/Button.js b/identity-apps-core/ui-components/Button.js deleted file mode 100644 index 8ece532b6cd..00000000000 --- a/identity-apps-core/ui-components/Button.js +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 LLC. (http://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. - */ - -const Button = ({ component, actionHandler }) => { - return ( -
- -
- ); -}; - -export default Button; diff --git a/identity-apps-core/ui-components/TextInput.js b/identity-apps-core/ui-components/TextInput.js deleted file mode 100644 index 7d99a84e193..00000000000 --- a/identity-apps-core/ui-components/TextInput.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 LLC. (http://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 { useEffect, useState } from 'react'; - -const TextInput = ({ component, formStateHandler }) => { - const [ value, setValue ] = useState(component.properties.value); - const [ hasError, setError ] = useState(false); - - useEffect(() => { - formStateHandler(component.properties.name, value); - }, [value]); - - return ( -
- -
- setValue(e.target.value)} - /> - -
- { hasError && ( -
- - Username cannot be empty. -
- ) } -
- ); -}; - -export default TextInput; diff --git a/identity-apps-core/ui-components/index.js b/identity-apps-core/ui-components/index.js deleted file mode 100644 index 250768eccd3..00000000000 --- a/identity-apps-core/ui-components/index.js +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2024, WSO2 LLC. (http://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 PageHead from './PageHead'; -import TextInput from './TextInput'; -import Button from './Button'; -import Form from './Form'; - -const RenderComponent = (component, actionHandler, formStateHandler) => { - switch (component.type) { - case 'pageHead': - return ( - <> - -
- - ); - case 'input': - case 'password': - return ( - <> - -
- - ); - case 'button': - return