@progress/sitefinity-nextjs-sdk
Version:
Provides OOB widgets developed using the Next.js framework, which includes an abstraction layer for Sitefinity communication. Additionally, it offers an expanded API, typings, and tools for further development and integration.
112 lines (111 loc) • 8.14 kB
JavaScript
'use client';
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import React, { useEffect } from 'react';
import { VisibilityStyle } from '../styling/visibility-style';
import { ExternalLoginBase } from '../external-login-base';
import { classNames } from '../../editor/utils/classNames';
import { SecurityService } from '../../services/security-service';
import { useSearchParams } from 'next/navigation';
import { getQueryParams } from '../common/query-params';
import { getUniqueId } from '../../editor/utils/getUniqueId';
const invalidDataAttr = 'data-sf-invalid';
const isValidEmail = function (email) {
return /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w+)+$/.test(email);
};
export function LoginFormClient(props) {
const searchParams = useSearchParams();
const usernameInputId = getUniqueId('sf-username-', props.widgetContext.model.Id);
const passwordInputId = getUniqueId('sf-password-', props.widgetContext.model.Id);
const rememberInputId = getUniqueId('sf-remember-', props.widgetContext.model.Id);
const labels = props.labels;
const visibilityClassHidden = props.visibilityClasses[VisibilityStyle.Hidden];
const returnUrl = ExternalLoginBase.GetDefaultReturnUrl(getQueryParams(searchParams), { redirectUrl: props.redirectUrl });
const returnErrorUrl = ExternalLoginBase.GetDefaultReturnUrl(getQueryParams(searchParams), { isError: true, shouldEncode: false });
const passResetColumnSize = props.rememberMe ? 'col-md-6 text-end' : 'col-12';
const formRef = React.useRef(null);
const emailInputRef = React.useRef(null);
const [invalidInputs, setInvalidInputs] = React.useState({});
const [showErrorMessage, setShowErrorMessage] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState(labels.errorMessage);
const [externalProvidersData, setExternalProvidersData] = React.useState([]);
const handleSubmit = (event) => {
event.preventDefault();
if (!validateForm(formRef.current)) {
return;
}
SecurityService.setAntiForgeryTokens().then(() => {
event.target.submit();
}, () => {
showError('AntiForgery token retrieval failed');
});
};
useEffect(() => {
const externalProviderData = props.externalProviders?.map(provider => {
const providerClass = ExternalLoginBase.GetExternalLoginButtonCssClass(provider.Name);
const externalLoginPath = ExternalLoginBase.GetExternalLoginPath(getQueryParams(searchParams), provider.Name);
return {
cssClass: providerClass,
externalLoginPath: externalLoginPath,
label: provider.Value
};
}) ?? [];
setExternalProvidersData(externalProviderData);
}, []);
const validateForm = (form) => {
let isValid = true;
setInvalidInputs({});
setShowErrorMessage(false);
let requiredInputs = form.querySelectorAll('input[data-sf-role=\'required\']');
const emptyInputs = {};
requiredInputs.forEach((input) => {
if (!input.value) {
invalidateElement(emptyInputs, input);
isValid = false;
}
});
if (!isValid) {
setErrorMessage(labels.validationRequiredMessage);
setShowErrorMessage(true);
setInvalidInputs(emptyInputs);
return isValid;
}
let emailInput = emailInputRef.current;
if (!isValidEmail(emailInput.value)) {
setErrorMessage(labels.validationInvalidEmailMessage);
invalidateElement(emptyInputs, emailInput);
setShowErrorMessage(true);
setInvalidInputs(emptyInputs);
return false;
}
return isValid;
};
const invalidateElement = (emptyInputs, element) => {
if (element) {
emptyInputs[element.name] = true;
}
};
const showError = (err) => {
setErrorMessage(err);
};
const inputValidationAttrs = (name) => {
return {
className: classNames('form-control', {
[props.invalidClass]: invalidInputs[name]
}),
[invalidDataAttr]: invalidInputs[name],
name: name
};
};
return (_jsxs(_Fragment, { children: [_jsxs("div", { "data-sf-role": "form-container", children: [_jsx("h2", { className: "mb-3", children: labels.header }), _jsx("div", { id: "errorContainer", className: classNames('alert alert-danger my-3', {
['d-block']: ExternalLoginBase.isError(getQueryParams(searchParams)) || showErrorMessage,
[visibilityClassHidden]: !(ExternalLoginBase.isError(getQueryParams(searchParams)) || showErrorMessage)
}), role: "alert", "aria-live": "assertive", "data-sf-role": "error-message-container", children: errorMessage }), _jsxs("form", { ref: formRef, onSubmit: handleSubmit, action: props.loginHandlerPath, method: "post", role: "form", noValidate: true, children: [_jsxs("div", { className: "mb-3", children: [_jsx("label", { htmlFor: usernameInputId, className: "form-label", children: labels.emailLabel }), _jsx("input", { type: "email", ref: emailInputRef, id: usernameInputId, "data-sf-role": "required", ...inputValidationAttrs('username') })] }), _jsxs("div", { className: "mb-3", children: [_jsx("label", { htmlFor: passwordInputId, className: "form-label", children: labels.passwordLabel }), _jsx("input", { type: "password", id: passwordInputId, "data-sf-role": "required", ...inputValidationAttrs('password') })] }), (props.rememberMe || props.forgottenPasswordLink) &&
_jsxs("div", { className: "row mb-3", children: [props.rememberMe &&
_jsx("div", { className: "checkbox col-md-6 m-0", children: _jsxs("label", { children: [_jsx("input", { defaultChecked: props.rememberMe, "data-val": "true", "data-val-required": "The RememberMe field is required.", id: rememberInputId, name: "RememberMe", type: "checkbox", defaultValue: `${props.rememberMe}` }), _jsx("label", { htmlFor: rememberInputId, children: labels.rememberMeLabel })] }) }), props.forgottenPasswordLink &&
_jsx("div", { className: passResetColumnSize, children: _jsx("a", { href: props.forgottenPasswordLink, className: "text-decoration-none", children: labels.forgottenPasswordLinkLabel }) })] }), _jsx("input", { type: "hidden", name: "RedirectUrl", value: returnUrl }), _jsx("input", { type: "hidden", name: "ErrorRedirectUrl", value: returnErrorUrl }), _jsx("input", { type: "hidden", name: "MembershipProviderName", value: props.membershipProviderName || '' }), _jsx("input", { type: "hidden", value: "", name: "sf_antiforgery" }), _jsx("input", { className: "btn btn-primary w-100", type: "submit", value: labels.submitButtonLabel || '' }), props.rememberMe && _jsx("input", { name: "RememberMe", type: "hidden", value: "false" })] }), _jsx("input", { type: "hidden", name: "ValidationInvalidEmailMessage", value: labels.validationInvalidEmailMessage || '' }), _jsx("input", { type: "hidden", name: "ValidationRequiredMessage", value: labels.validationRequiredMessage || '' })] }), props.registrationLink &&
_jsxs("div", { className: "row mt-3", children: [_jsx("div", { className: "col-md-6", children: labels.notRegisteredLabel }), _jsx("div", { className: "col-md-6 text-end", children: _jsx("a", { href: props.registrationLink, className: "text-decoration-none", children: labels.registerLinkText }) })] }), externalProvidersData.length > 0 &&
(_jsxs(_Fragment, { children: [_jsx("h3", { className: "mt-3", children: labels.externalProvidersHeader }), externalProvidersData.map((providerData, idx) => {
return (_jsx("a", { className: classNames('btn border fs-5 w-100 mt-2', providerData.cssClass), href: providerData.externalLoginPath, children: providerData.label }, idx));
})] }))] }));
}
;