Skip to content

Commit

Permalink
feat(user): implemented create account logic
Browse files Browse the repository at this point in the history
  • Loading branch information
RCVZ committed Jul 29, 2021
1 parent 8b5105b commit 58eff73
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 28 deletions.
2 changes: 1 addition & 1 deletion src/containers/AccountModal/forms/PersonalDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ const PersonalDetails = () => {
};

const yepSchema: unknown = getCaptureFields(dummy).fields.reduce(createYupSchema, {});
console.info(yepSchema);

const validationSchema: SchemaOf<PersonalDetailsFormData> = object().shape(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
yepSchema as Record<string, AnySchema<any, any, any> | Lazy<any, any> | Reference<unknown>>,
Expand Down
84 changes: 61 additions & 23 deletions src/containers/AccountModal/forms/Registration.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,63 @@
import React from 'react';
import { object, string, SchemaOf, boolean } from 'yup';
import type { RegistrationFormData } from 'types/account';
import React, { useEffect, useState } from 'react';
import { object, string, SchemaOf } from 'yup';
import type { RegistrationFormData, ConsentsFormData } from 'types/account';
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router';
import { useQuery } from 'react-query';

import { getPublisherConsents } from '../../../services/account.service';
import RegistrationForm from '../../../components/RegistrationForm/RegistrationForm';
import useForm, { UseFormOnSubmitHandler } from '../../../hooks/useForm';
import { addQueryParam } from '../../../utils/history';

//todo add registration logic

const temp = (t: unknown) => {
t;
};
import { ConfigStore } from '../../../stores/ConfigStore';
import { extractConsentValues, checkConsentsFromValues } from '../../../utils/collection';
import { register, updateConsents } from '../../../stores/AccountStore';

const Registration = () => {
const history = useHistory();
const { t } = useTranslation('account');
const registrationSubmitHandler: UseFormOnSubmitHandler<RegistrationFormData> = async (formData, { setErrors, setSubmitting, setValue }) => {
const { cleengId, cleengSandbox: sandbox } = ConfigStore.useState((s) => s.config);
const [consentsFormData, updateConsentsFormData] = useState<ConsentsFormData>({});
const [consentsError, setConsentsError] = useState<string[]>([]);

const publisherId = cleengId || '';
const enabled = !!publisherId;
const getConsents = () => getPublisherConsents({ publisherId }, sandbox);
const { data: publisherConsents, isLoading: publisherConsentsLoading } = useQuery(['consents'], getConsents, { enabled });

const handleChangeConsent = (event: React.ChangeEvent<HTMLInputElement>) => {
updateConsentsFormData((current) => ({ ...current, [event.target.name]: event.target.checked }));
};

useEffect(() => {
updateConsentsFormData(extractConsentValues(publisherConsents?.responseData.consents));
}, [publisherConsents?.responseData.consents]);

const registrationSubmitHandler: UseFormOnSubmitHandler<RegistrationFormData> = async (
{ email, password },
{ setErrors, setSubmitting, setValue },
) => {
try {
await temp(formData);
const { consentsErrors, customerConsents } = checkConsentsFromValues(publisherConsents?.responseData.consents, consentsFormData);

if (consentsErrors.length) {
setConsentsError(consentsErrors);
throw new Error('consent required');
}

await register(email, password);
await updateConsents(customerConsents);

history.push(addQueryParam(history, 'u', 'personal-details'));
} catch (error: unknown) {
if (error instanceof Error) {
if (error.message.toLowerCase().includes('invalid param email')) {
setErrors({ email: t('registration.invalid_email') });
} else if (error.message.toLowerCase().includes('invalid param password')) {
const errorMessage = error.message.toLowerCase();
if (errorMessage.includes('customer already exists.')) {
setErrors({ form: t('registration.user_exists') });
} else if (errorMessage.includes('invalid param password')) {
setErrors({ form: t('registration.invalid_password') });
} else if (errorMessage.includes('consent required')) {
setErrors({ form: t('registration.field_required') });
}
setValue('password', '');
}
Expand All @@ -39,17 +69,25 @@ const Registration = () => {
const validationSchema: SchemaOf<RegistrationFormData> = object().shape({
email: string().email(t('registration.field_is_not_valid_email')).required(t('registration.field_required')),
password: string().required(t('registration.field_required')),
termsConditions: boolean().required(t('registration.field_required')),
emailUpdates: boolean().required(),
});
const initialValues: RegistrationFormData = { email: '', password: '', termsConditions: true, emailUpdates: true };
const { handleSubmit, handleChange, values, errors, submitting } = useForm<RegistrationFormData>(
initialValues,
registrationSubmitHandler,
validationSchema,
);

return <RegistrationForm onSubmit={handleSubmit} onChange={handleChange} values={values} errors={errors} submitting={submitting} />;
const initialRegistrationValues: RegistrationFormData = { email: '', password: '' };
const { handleSubmit, handleChange, values, errors, submitting } = useForm(initialRegistrationValues, registrationSubmitHandler, validationSchema);

return (
<RegistrationForm
onSubmit={handleSubmit}
onChange={handleChange}
values={values}
errors={errors}
consentsError={consentsError}
submitting={submitting}
consentsFormData={consentsFormData}
publisherConsents={publisherConsents?.responseData.consents}
loading={publisherConsentsLoading}
onChangeConsent={handleChangeConsent}
/>
);
};

export default Registration;
48 changes: 46 additions & 2 deletions src/stores/AccountStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Store } from 'pullstate';
import jwtDecode from 'jwt-decode';

import * as accountService from '../services/account.service';
import type { AuthData, Customer, JwtDetails } from '../../types/account';
import type { AuthData, Customer, JwtDetails, CustomerConsent } from '../../types/account';
import * as persist from '../utils/persist';

import { ConfigStore } from './ConfigStore';
Expand Down Expand Up @@ -65,7 +65,7 @@ const refreshJwtToken = async (sandbox: boolean, auth: AuthData) => {
}
};

const afterLogin = async (sandbox: boolean, auth: AuthData) => {
export const afterLogin = async (sandbox: boolean, auth: AuthData) => {
const decodedToken: JwtDetails = jwtDecode(auth.jwt);
const customerId = decodedToken.customerId.toString();
const response = await accountService.getCustomer({ customerId }, sandbox, auth.jwt);
Expand All @@ -91,3 +91,47 @@ export const login = async (email: string, password: string) => {

return afterLogin(cleengSandbox, response.responseData);
};

export const register = async (email: string, password: string) => {
const {
config: { cleengId, cleengSandbox },
} = ConfigStore.getRawState();

if (!cleengId) throw new Error('cleengId is not configured');

const localesResponse = await accountService.getLocales(cleengSandbox);

if (localesResponse.errors.length > 0) throw new Error(localesResponse.errors[0]);

const responseRegister = await accountService.register(
{
email: email,
password: password,
locale: localesResponse.responseData.locale,
country: localesResponse.responseData.country,
currency: localesResponse.responseData.currency,
publisherId: cleengId,
},
cleengSandbox,
);

if (responseRegister.errors.length) throw new Error(responseRegister.errors[0]);

return afterLogin(cleengSandbox, responseRegister.responseData);
};

export const updateConsents = async (customerConsents: CustomerConsent[]) => {
const { auth, user } = AccountStore.getRawState();
const {
config: { cleengSandbox },
} = ConfigStore.getRawState();

if (!auth || !user) throw new Error('no auth');

const updateConsentsResponse = await accountService.updateCustomerConsents(
{ id: user.id.toString(), consents: customerConsents },
cleengSandbox,
auth.jwt,
);
if (updateConsentsResponse.errors.length) throw new Error(updateConsentsResponse.errors[0]);
};
1 change: 1 addition & 0 deletions src/styles/_theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ $text-field-error-color: #ff0c3e !default;
// Input
$input-resting-border-color: rgba(variables.$white, 0.34) !default;
$input-hover-border-color: rgba(variables.$white, 0.7) !default;
$input-field-error-color: #ff0c3e !default;

// Toggle

Expand Down
37 changes: 37 additions & 0 deletions src/utils/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,20 @@ const formatConsentValues = (publisherConsents?: Consent[], customerConsents?: C
return values;
};

const extractConsentValues = (consents?: Consent[]) => {
const values: Record<string, boolean> = {};

if (!consents) {
return values;
}

consents?.forEach((consent) => {
values[consent.name] = consent.enabledByDefault;
});

return values;
};

const formatConsentsFromValues = (publisherConsents?: Consent[], values?: GenericFormValues) => {
const consents: CustomerConsent[] = [];

Expand All @@ -91,6 +105,27 @@ const formatConsentsFromValues = (publisherConsents?: Consent[], values?: Generi
return consents;
};

const checkConsentsFromValues = (publisherConsents?: Consent[], consents?: GenericFormValues) => {
const customerConsents: CustomerConsent[] = [];
const consentsErrors: string[] = [];

if (!publisherConsents || !consents) return { customerConsents, consentsErrors };

publisherConsents.forEach((consent) => {
if (consent.required && !consents[consent.name]) {
consentsErrors.push(consent.name);
}

customerConsents.push({
name: consent.name,
version: consent.version,
state: consents[consent.name] ? 'accepted' : 'declined',
});
});

return { customerConsents, consentsErrors };
};

export {
getFiltersFromConfig,
getFiltersFromSeries,
Expand All @@ -101,4 +136,6 @@ export {
generatePlaylistPlaceholder,
formatConsentValues,
formatConsentsFromValues,
extractConsentValues,
checkConsentsFromValues,
};
7 changes: 5 additions & 2 deletions types/account.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ export type LoginFormData = {
export type RegistrationFormData = {
email: string;
password: string;
termsConditions: boolean;
emailUpdates: boolean;
};

export type ConsentsFormData = {
[key: string]: boolean;
};

export type OfferPeriodicity = 'monthly' | 'yearly';
Expand Down Expand Up @@ -135,6 +137,7 @@ export type Consent = {
version: string;
value: string;
label: string;
enabledByDefault: boolean;
required: boolean;
};
export type CustomerConsent = {
Expand Down

0 comments on commit 58eff73

Please sign in to comment.