Skip to content

Commit

Permalink
feat: registration flow
Browse files Browse the repository at this point in the history
  • Loading branch information
kiremitrov123 committed Dec 5, 2022
1 parent f309cbf commit 435029a
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 111 deletions.
5 changes: 4 additions & 1 deletion src/containers/AccountModal/forms/Registration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,13 @@ const Registration = () => {
} catch (error: unknown) {
if (error instanceof Error) {
const errorMessage = error.message.toLowerCase();
if (errorMessage.includes('customer already exists.')) {
if (errorMessage.includes('already exists')) {
setErrors({ form: t('registration.user_exists') });
} else if (errorMessage.includes('invalid param password')) {
setErrors({ password: t('registration.invalid_password') });
} else {
// in case the endpoint fails
setErrors({ password: t('registration.failed_to_create') });
}
setValue('password', '');
}
Expand Down
3 changes: 2 additions & 1 deletion src/i18n/locales/en_US/account.json
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@
"sign_up": "Sign up",
"user_exists": "There is already a user with this email address",
"view_password": "View password",
"email_updates": "Yes, I want to receive {{siteName}} updates by email."
"email_updates": "Yes, I want to receive {{siteName}} updates by email.",
"failed_to_create": "Unable to register at the moment."
},
"renew_subscription": {
"explanation": "By clicking the button below you can renew your plan.",
Expand Down
75 changes: 52 additions & 23 deletions src/services/cleeng.account.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import type {
AuthData,
JwtDetails,
RegisterPayload,
GetPublisherConsentsResponse,
GetCustomerConsentsResponse,
GetCaptureStatusResponse,
Capture,
} from '#types/account';
import type { Config } from '#types/Config';

Expand Down Expand Up @@ -82,24 +86,61 @@ export async function getUser({ config, auth }: { config: Config; auth: AuthData
}

export const getFreshJwtToken = async ({ config, auth }: { config: Config; auth: AuthData }) => {
const result = await refreshToken({ refreshToken: auth.refreshToken }, !!config.integrations.cleeng?.useSandbox);
const response = await refreshToken({ refreshToken: auth.refreshToken }, !!config.integrations.cleeng?.useSandbox);

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

return result?.responseData;
return response?.responseData;
};

// export const register: Register = async (payload, sandbox) => {
// payload.customerIP = getOverrideIP();
// return post(sandbox, '/customers', JSON.stringify(payload));
// };
export const getPublisherConsents: GetPublisherConsents = async (config) => {
const { cleeng } = config.integrations;
const response: ServiceResponse<GetPublisherConsentsResponse> = await get(!!cleeng?.useSandbox, `/publishers/${cleeng?.id}/consents`);

export const fetchPublisherConsents: GetPublisherConsents = async (payload, sandbox) => {
return get(sandbox, `/publishers/${payload.publisherId}/consents`);
if (response.errors.length) throw new Error(response.errors[0]);

return response;
};

export const getCustomerConsents: GetCustomerConsents = async (payload) => {
const { config, customer, jwt } = payload;
const { cleeng } = config.integrations;

const response: ServiceResponse<GetCustomerConsentsResponse> = await get(!!cleeng?.useSandbox, `/customers/${customer?.id}/consents`, jwt);
if (response.errors.length) throw new Error(response.errors[0]);

return response;
};

export const fetchCustomerConsents: GetCustomerConsents = async (payload, sandbox, jwt) => {
return get(sandbox, `/customers/${payload.customerId}/consents`, jwt);
export const updateCustomerConsents: UpdateCustomerConsents = async (payload) => {
const { config, customer, jwt } = payload;
const { cleeng } = config.integrations;

const _payload = {
id: customer.id,
consents: payload.consents,
};

const response: ServiceResponse<never> = await put(!!cleeng?.useSandbox, `/customers/${customer?.id}/consents`, JSON.stringify(_payload), jwt);
if (response.errors.length) throw new Error(response.errors[0]);

return response;
};

export const getCaptureStatus: GetCaptureStatus = async ({ customer }, sandbox, jwt) => {
const response: ServiceResponse<GetCaptureStatusResponse> = await get(sandbox, `/customers/${customer?.id}/capture/status`, jwt);

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

return response;
};

export const updateCaptureAnswers: UpdateCaptureAnswers = async ({ customer, ...payload }, sandbox, jwt) => {
const response: ServiceResponse<Capture> = await put(sandbox, `/customers/${customer.id}/capture`, JSON.stringify(payload), jwt);

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

return response;
};

export const resetPassword: ResetPassword = async (payload, sandbox) => {
Expand All @@ -114,10 +155,6 @@ export const updateCustomer: UpdateCustomer = async (payload, sandbox, jwt) => {
return patch(sandbox, `/customers/${payload.id}`, JSON.stringify(payload), jwt);
};

export const updateCustomerConsents: UpdateCustomerConsents = async (payload, sandbox, jwt) => {
return put(sandbox, `/customers/${payload.id}/consents`, JSON.stringify(payload), jwt);
};

export const getCustomer: GetCustomer = async (payload, sandbox, jwt) => {
return get(sandbox, `/customers/${payload.customerId}`, jwt);
};
Expand All @@ -129,11 +166,3 @@ export const refreshToken: RefreshToken = async (payload, sandbox) => {
export const getLocales: GetLocales = async (sandbox) => {
return get(sandbox, `/locales${getOverrideIP() ? '?customerIP=' + getOverrideIP() : ''}`);
};

export const getCaptureStatus: GetCaptureStatus = async ({ customerId }, sandbox, jwt) => {
return get(sandbox, `/customers/${customerId}/capture/status`, jwt);
};

export const updateCaptureAnswers: UpdateCaptureAnswers = async ({ customerId, ...payload }, sandbox, jwt) => {
return put(sandbox, `/customers/${customerId}/capture`, JSON.stringify(payload), jwt);
};
194 changes: 165 additions & 29 deletions src/services/inplayer.account.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import InPlayer, { AccountData, Env } from '@inplayer-org/inplayer.js';
import InPlayer, { AccountData, Env, GetRegisterField } from '@inplayer-org/inplayer.js';

import type { AuthData, Customer, CustomerConsent, Login, Register, UpdateCustomer } from '#types/account';
import type {
AuthData,
Capture,
Consent,
Customer,
CustomerConsent,
GetCaptureStatus,
GetCaptureStatusResponse,
GetCustomerConsentsPayload,
GetPublisherConsents,
Login,
Register,
UpdateCaptureAnswers,
UpdateCustomer,
UpdateCustomerConsents,
} from '#types/account';
import type { Config } from '#types/Config';
import type { InPlayerAuthData } from '#types/inplayer';
import type { InPlayerAuthData, InPlayerError } from '#types/inplayer';

enum InPlayerEnv {
Development = 'development',
Expand All @@ -25,8 +40,8 @@ export const login: Login = async ({ config, email, password }) => {
});

return {
auth: processInPlayerAuth(data),
user: processInplayerAccount(data.account),
auth: processAuth(data),
user: processAccount(data.account),
};
} catch {
throw new Error('Failed to authenticate user.');
Expand All @@ -39,18 +54,19 @@ export const register: Register = async ({ config, email, password }) => {
email,
password,
passwordConfirmation: password,
fullName: '',
fullName: 'New User',
type: 'consumer',
clientId: config.integrations.inplayer?.clientId || '',
referrer: window.location.href,
});

return {
auth: processInPlayerAuth(data),
user: processInplayerAccount(data.account),
auth: processAuth(data),
user: processAccount(data.account),
};
} catch {
throw new Error('Failed to create user.');
} catch (error: unknown) {
const { response } = error as InPlayerError;
throw new Error(response.data.message);
}
};

Expand All @@ -65,7 +81,7 @@ export const logout = async () => {
export const getUser = async (): Promise<Customer> => {
try {
const { data } = await InPlayer.Account.getAccountInfo();
return processInplayerAccount(data);
return processAccount(data);
} catch {
throw new Error('Failed to fetch user data.');
}
Expand All @@ -75,54 +91,174 @@ export const getFreshJwtToken = async ({ auth }: { auth: AuthData }) => auth;

export const updateCustomer: UpdateCustomer = async (values) => {
try {
const consents: { [key: string]: string } = {};
values.consents?.map((consent: CustomerConsent) => {
if (consent.label) {
const { customerId, date, newestVersion, needsUpdate, ...rest } = consent;
consents[`consents_${consent.name}`] = JSON.stringify(rest);
}
});
const fullName = `${values.firstName} ${values.lastName}`;
const consents = processCustomerConsents(values?.consents || []);

const response = await InPlayer.Account.updateAccount({
fullName: `${values.firstName} ${values.lastName}`,
fullName,
metadata: {
first_name: values.firstName as string,
last_name: values.lastName as string,
firstName: values.firstName as string,
lastName: values.lastName as string,
...consents,
},
});

return {
errors: [],
// @ts-ignore
// wrong data type from InPlayer SDK
responseData: processInplayerAccount(response.data),
// wrong data type from InPlayer SDK (will be updated in the SDK)
responseData: processAccount(response.data),
};
} catch {
throw new Error('Failed to fetch user data.');
throw new Error('Failed to update user data.');
}
};

export const getPublisherConsents: GetPublisherConsents = async (config) => {
try {
const { inplayer } = config.integrations;
const { data } = await InPlayer.Account.getRegisterFields(inplayer?.clientId || '');

// @ts-ignore
// wrong data type from InPlayer SDK (will be updated in the SDK)
const result: Array<Consent> = data?.collection
.filter((field: GetRegisterField) => field.type === 'checkbox')
.map((consent: GetRegisterField) => processPublisherConsents(consent));

return {
errors: [],
responseData: {
consents: [getTermsConsent(), ...result],
},
};
} catch {
throw new Error('Failed to fetch publisher consents.');
}
};

export const getCustomerConsents = async (payload: GetCustomerConsentsPayload) => {
try {
const { customer } = payload;

if (!customer?.metadata) {
return {
errors: [],
responseData: {
consents: [],
},
};
}

const consents = Object.keys(customer.metadata)
.filter((key) => key.includes('consents_'))
.map((key) => JSON.parse(customer.metadata?.[key] as string));

return {
errors: [],
responseData: {
consents,
},
};
} catch {
throw new Error('Unable to fetch Customer consents.');
}
};

export const updateCustomerConsents: UpdateCustomerConsents = async (payload) => {
try {
const { customer, consents } = payload;

const data = {
consents,
firstName: customer.metadata?.firstName as string,
lastName: customer.metadata?.lastName as string,
};

return (await updateCustomer(data, true, '')) as ServiceResponse<never>;
} catch {
throw new Error('Unable to update Customer`s consents');
}
};
// responsible to convert the InPlayer object to be compatible to the store
function processInplayerAccount(account: AccountData): Customer {

export const getCaptureStatus: GetCaptureStatus = async ({ customer }) => {
return {
errors: [],
responseData: {
isCaptureEnabled: true,
shouldCaptureBeDisplayed: true,
settings: [
{
answer: {
firstName: customer.firstName || null,
lastName: customer.lastName || null,
},
enabled: true,
key: 'firstNameLastName',
required: true,
},
],
},
} as ServiceResponse<GetCaptureStatusResponse>;
};

export const updateCaptureAnswers: UpdateCaptureAnswers = async ({ ...metadata }) => {
return (await updateCustomer(metadata, true, '')) as ServiceResponse<Capture>;
};

function processAccount(account: AccountData): Customer {
const { id, email, full_name: fullName, metadata, created_at: createdAt } = account;
const regDate = new Date(createdAt * 1000).toLocaleString();

return {
id: id.toString(),
email,
fullName,
firstName: metadata?.first_name as string,
lastName: metadata?.last_name as string,
metadata,
firstName: metadata?.firstName as string,
lastName: metadata?.lastName as string,
regDate,
country: '',
lastUserIp: '',
};
}

function processInPlayerAuth(auth: InPlayerAuthData): AuthData {
function processAuth(auth: InPlayerAuthData): AuthData {
const { access_token: jwt } = auth;
return {
jwt,
customerToken: '',
refreshToken: '',
};
}

function processPublisherConsents(consent: Partial<GetRegisterField>) {
return {
broadcasterId: 0,
enabledByDefault: false,
label: consent.label,
name: consent.name,
required: consent.required,
value: '',
version: '1',
} as Consent;
}

function processCustomerConsents(consents: CustomerConsent[]) {
const result: { [key: string]: string } = {};
consents?.forEach((consent: CustomerConsent) => {
if (consent.name) {
const { name, version, state } = consent;
result[`consents_${consent.name}`] = JSON.stringify({ name, version, state });
}
});
return result;
}

function getTermsConsent(): Consent {
const label = 'I accept the <a href="https://inplayer.com/legal/terms" target="_blank">Terms and Conditions</a> of InPlayer.';
return processPublisherConsents({
required: true,
name: 'terms',
label,
});
}
Loading

0 comments on commit 435029a

Please sign in to comment.