Skip to content

Commit

Permalink
Fix conflict
Browse files Browse the repository at this point in the history
  • Loading branch information
eunjuhuss committed May 28, 2024
2 parents c8dc4ff + 872247b commit 8c1ef2f
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 167 deletions.
4 changes: 4 additions & 0 deletions src/apis/eduidSignup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ export const acceptToURequest = createAsyncThunk<

export interface RegisterEmailRequest {
email: string;
given_name: string;
surname: string;
}

/**
Expand All @@ -154,6 +156,8 @@ export const registerEmailRequest = createAsyncThunk<
>("signup/registerEmailRequest", async (args, thunkAPI) => {
const body: KeyValues = {
email: args.email,
surname: args.surname,
given_name: args.given_name,
};

return makeSignupRequest<SignupStatusResponse>(thunkAPI, "register-email", body)
Expand Down
2 changes: 1 addition & 1 deletion src/components/Common/EmailInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const emailPlaceHolder = "[email protected]";

interface EmailInputProps {
required: boolean;
autoFocus: boolean;
autoFocus?: boolean;
name: string;
autoComplete?: "username";
helpBlock?: React.ReactNode; // help text shown above input
Expand Down
103 changes: 36 additions & 67 deletions src/components/Dashboard/VerifyIdentity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,80 +156,49 @@ function VerifiedIdentitiesTable(): JSX.Element {
return (
<React.Fragment>
{identities.nin?.verified && (
<figure className="table-responsive identity-summary">
<table className="table">
<tbody>
<tr className="border-row">
<td>
<img height="35" className="circle-icon" alt="Sweden" src={SeFlag} />
</td>
<td>
<strong>
<FormattedMessage
defaultMessage="Swedish national identity number"
description="Verified identity"
/>
</strong>
</td>
<td>
<NinDisplay nin={identities.nin} allowDelete={true} />
</td>
</tr>
</tbody>
</table>
<figure className="grid-container identity-summary">
<div>
<img height="35" className="circle-icon" alt="Sweden" src={SeFlag} />
</div>
<div className="profile-grid-cell">
<strong>
<FormattedMessage defaultMessage="Swedish national identity number" description="Verified identity" />
</strong>
</div>
<NinDisplay nin={identities.nin} allowDelete={true} />
</figure>
)}

{identities.eidas?.verified && (
<React.Fragment>
<figure className="table-responsive identity-summary">
<table className="table">
<tbody>
<tr className="border-row">
<td>
<img height="35" className="circle-icon" alt="European Union" src={EuFlag} />
</td>
<td>
<strong>
<FormattedMessage defaultMessage="European EIDAS identity" description="Verified identity" />
</strong>
</td>
<td>
{identities.eidas.country_code}&nbsp;{identities.eidas.date_of_birth}
</td>
</tr>
</tbody>
</table>
</figure>
</React.Fragment>
<figure className="grid-container identity-summary">
<div>
<img height="35" className="circle-icon" alt="European Union" src={EuFlag} />
</div>
<div className="profile-grid-cell">
<strong>
<FormattedMessage defaultMessage="European EIDAS identity" description="Verified identity" />
</strong>
</div>
{identities.eidas.country_code}&nbsp;{identities.eidas.date_of_birth}
</figure>
)}

{identities.svipe?.verified && (
<React.Fragment>
<figure className="table-responsive identity-summary">
<table className="table">
<tbody>
<tr className="border-row">
<td>
<ReactCountryFlag
className="flag-icon"
aria-label={regionNames.of(identities.svipe.country_code)}
countryCode={identities.svipe.country_code}
/>
</td>
<td>
<strong>
<FormattedMessage defaultMessage="Foreign Svipe identity" description="Verified identity" />
</strong>
</td>
<td>
{regionNames.of(identities.svipe.country_code)}&nbsp;{identities.svipe.date_of_birth}
</td>
</tr>
</tbody>
</table>
</figure>
</React.Fragment>
<figure className="grid-container identity-summary">
<div>
<ReactCountryFlag
className="flag-icon"
aria-label={regionNames.of(identities.svipe.country_code)}
countryCode={identities.svipe.country_code}
/>
</div>
<div className="profile-grid-cell">
<strong>
<FormattedMessage defaultMessage="Foreign Svipe identity" description="Verified identity" />
</strong>
</div>
{regionNames.of(identities.svipe.country_code)}&nbsp;{identities.svipe.date_of_birth}
</figure>
)}
{/* verifying with Swedish national number in accordion only possible for users already verified with Eidas or Svipe */}
{!identities.nin?.verified && (
Expand Down
10 changes: 6 additions & 4 deletions src/components/Help.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1323,10 +1323,12 @@ export function Help(): JSX.Element {
/>
</li>
<li>
<FormattedMessage
description="how to contact support - list item 2"
defaultMessage="Don't include confidential or sensitive information such as your personal identity number in the email!"
/>
<strong>
<FormattedMessage
description="how to contact support - list item 2"
defaultMessage="Don't include confidential or sensitive information such as your personal identity number in the email!"
/>
</strong>
</li>
<li>
<FormattedMessage
Expand Down
64 changes: 55 additions & 9 deletions src/components/Signup/SignupEmailForm.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { registerEmailRequest } from "apis/eduidSignup";
import CustomInput from "components/Common/CustomInput";
import EduIDButton from "components/Common/EduIDButton";
import EmailInput from "components/Common/EmailInput";
import { SignupGlobalStateContext } from "components/Signup/SignupGlobalState";
import { useAppDispatch, useAppSelector } from "eduid-hooks";
import { validateSignupUserInForm } from "helperFunctions/validation/validateEmail";
import { Fragment, useContext, useEffect } from "react";
import { Form as FinalForm, FormRenderProps } from "react-final-form";
import { FormattedMessage } from "react-intl";
import { Field as FinalField, Form as FinalForm, FormRenderProps } from "react-final-form";
import { FormattedMessage, useIntl } from "react-intl";
import { clearNotifications } from "slices/Notifications";
import { signupSlice } from "slices/Signup";

Expand Down Expand Up @@ -33,20 +35,41 @@ export function SignupEmailForm(): JSX.Element {

interface EmailFormData {
email?: string;
given_name?: string;
surname?: string;
}

/* FORM */
function EmailForm() {
const dispatch = useAppDispatch();
const signupContext = useContext(SignupGlobalStateContext);
const intl = useIntl();

const firstNamePlaceholder = intl.formatMessage({
id: "placeholder.firstName",
defaultMessage: "First name",
description: "placeholder First name",
});

const lastNamePlaceholder = intl.formatMessage({
id: "placeholder.lastName",
defaultMessage: "Last name",
description: "placeholder Last name",
});

function submitEmailForm(values: EmailFormData) {
const errors: EmailFormData = {};

if (values.email) {
if (values) {
// We ask for the e-mail address first, but we don't pass it to the backend until the user has accepted the ToU
// terms of use, and solved a captcha. So we store it in the redux state here.
dispatch(signupSlice.actions.setEmail(values.email));
dispatch(
signupSlice.actions.setEmail({
email: values.email ?? "",
given_name: values.given_name ?? "",
surname: values.surname ?? "",
})
);
dispatch(clearNotifications());
signupContext.signupService.send({ type: "COMPLETE" });
} else {
Expand All @@ -58,16 +81,36 @@ function EmailForm() {
return (
<FinalForm<EmailFormData>
onSubmit={submitEmailForm}
validate={validateSignupUserInForm}
initialValues={{
email: "",
given_name: "",
surname: "",
}}
render={(formProps: FormRenderProps<EmailFormData>) => {
const _submitError = Boolean(formProps.submitError && !formProps.dirtySinceLastSubmit);
const _disabled = Boolean(formProps.hasValidationErrors || _submitError || formProps.pristine);

return (
<form id="register-form" onSubmit={formProps.handleSubmit}>
<EmailInput name="email" autoFocus={true} required={true} autoComplete="username" />
<FinalField
component={CustomInput}
type="text"
name="given_name"
autoFocus={true}
required={true}
placeholder={firstNamePlaceholder}
label={<FormattedMessage defaultMessage="First name" description="signup first name" />}
/>
<FinalField
component={CustomInput}
type="text"
name="surname"
required={true}
placeholder={lastNamePlaceholder}
label={<FormattedMessage defaultMessage="Last name" description="signup last name" />}
/>
<EmailInput name="email" required={true} autoComplete="username" />
<div className="buttons">
<EduIDButton
buttonstyle="primary"
Expand All @@ -92,14 +135,17 @@ export function RegisterEmail() {
const dispatch = useAppDispatch();
const signupContext = useContext(SignupGlobalStateContext);
const email = useAppSelector((state) => state.signup.email);
const given_name = useAppSelector((state) => state.signup.given_name);
const surname = useAppSelector((state) => state.signup.surname);
const signupUser = { email: email ?? "", given_name: given_name ?? "", surname: surname ?? "" };

if (!email) {
if (!signupUser) {
signupContext.signupService.send({ type: "API_FAIL" });
return null;
}

async function registerEmail(email: string) {
const res = await dispatch(registerEmailRequest({ email }));
async function registerEmail(signupUser: { email: string; given_name: string; surname: string }) {
const res = await dispatch(registerEmailRequest(signupUser));

if (registerEmailRequest.fulfilled.match(res)) {
signupContext.signupService.send({ type: "API_SUCCESS" });
Expand All @@ -109,7 +155,7 @@ export function RegisterEmail() {
}

useEffect(() => {
registerEmail(email);
registerEmail(signupUser);
}, []);

// Show a blank screen while we wait for the response from the backend
Expand Down
26 changes: 18 additions & 8 deletions src/helperFunctions/validation/validateEmail.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,46 @@
import { emailPattern } from "./regexPatterns";
import { emailPattern, emptyStringPattern } from "./regexPatterns";

interface EmailData {
email?: string;
given_name?: string;
surname?: string;
[key: string]: any;
}

/**
* Validate that the value is a plausible e-mail address. The returned string should be a translate() lookup key.
* @param values
* @returns
*/
export function validateEmailInForm(values: EmailData): EmailData {
export function validateSignupUserInForm(values: EmailData): EmailData {
const errors: EmailData = {};
if (values !== undefined) {
errors.email = validateEmailField(values.email);
["email", "given_name", "surname"].forEach((inputName) => {
if (!values[inputName] || emptyStringPattern.test(values[inputName])) {
errors[inputName] = "required";
}
});
if (values.email) {
const emailError = validateEmailField(values.email);
if (emailError) {
errors.email = emailError;
}
}
}

return errors;
}

// backwards compat export
export const validate = validateEmailInForm;
export const validate = validateSignupUserInForm;

/**
* Validate that the value is a plausible e-mail address. The returned string should be a translate() lookup key.
* @param values
* @returns
*/
export function validateEmailField(value?: string): string | undefined {
if (!value) {
return "required";
}
if (!emailPattern.test(value)) {
if (value && !emailPattern.test(value)) {
return "email.invalid_email";
}
}
8 changes: 6 additions & 2 deletions src/slices/Signup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
interface SignupState {
state?: SignupBackendState;
email?: string; // pass email address from one state to another
given_name?: string;
surname?: string;
email_code?: string; // pass email code from one state to another
captcha?: CaptchaRequest; // pass captcha response from one state to another
tou_accepted: boolean; // OLD: remove after one release
Expand All @@ -34,8 +36,10 @@ export const signupSlice = createSlice({
name: "signup",
initialState,
reducers: {
setEmail: (state, action: PayloadAction<string | undefined>) => {
state.email = action.payload;
setEmail: (state, action: PayloadAction<{ email: string; given_name: string; surname: string }>) => {
state.email = action.payload.email;
state.given_name = action.payload.given_name;
state.surname = action.payload.surname;
},
setEmailCode: (state, action: PayloadAction<string | undefined>) => {
state.email_code = action.payload;
Expand Down
19 changes: 19 additions & 0 deletions src/styles/_figure.scss
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ figure,
&.tight {
padding: 0.5em 1em;
}
&.grid-container {
display: grid;
grid-template-columns: 10% 40% 50%;
text-align: left;
vertical-align: middle;
line-height: 1;

img {
height: 1.5rem;
}
> div {
padding: 0.5rem 0.5rem;
align-self: center;

.display-data.verified {
font-size: 1rem;
}
}
}
}

.captcha-responsive {
Expand Down
Loading

0 comments on commit 8c1ef2f

Please sign in to comment.