Skip to content

Commit

Permalink
Merge pull request #735 from Real-Dev-Squad/onboarding/signup-api
Browse files Browse the repository at this point in the history
Integrate signup api in onboarding
  • Loading branch information
satyam73 authored Dec 27, 2023
2 parents dca3ef2 + 1eb7b00 commit f41ad60
Show file tree
Hide file tree
Showing 10 changed files with 247 additions and 99 deletions.
5 changes: 5 additions & 0 deletions app/adapters/application.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import JSONAPIAdapter from '@ember-data/adapter/json-api';
import { APPS } from 'website-www/constants/urls';

export default class ApplicationAdapter extends JSONAPIAdapter {
host = APPS.API_BACKEND;

headers = {
'Content-Type': 'application/json',
};

ajaxOptions() {
const options = super.ajaxOptions(...arguments);
options.credentials = 'include';
Expand Down
11 changes: 11 additions & 0 deletions app/adapters/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,15 @@ export default class UserAdapter extends ApplicationAdapter {
}
return super.urlForQuery(...arguments);
}

urlForQueryRecord(query) {
if (query.firstname && query.lastname) {
return `${super.urlForQueryRecord(...arguments)}/username`;
}
return super.urlForQueryRecord(...arguments);
}

urlForUpdateRecord() {
return `${this.host}/users/self`;
}
}
18 changes: 2 additions & 16 deletions app/components/signup-steps/step-one.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,6 @@
<div class='error__message'>{{this.errorMessage.lastname}}</div>
{{/if}}

<Reusables::OnboardingInput
@field='Username'
@name='username'
@type='text'
@required={{true}}
@value={{this.data.username}}
@isValid={{this.isValid}}
@hasButtonInsideInput={{true}}
@classDisableInput='input-disable'
@onClickGetUsername={{this.getUsername}}
@onInput={{this.inputHandler}}
@disabled={{true}}
/>

<Reusables::Dropdown
@field='Select your role'
@name='role'
Expand Down Expand Up @@ -79,9 +65,9 @@
<Reusables::Button
@text='Signup'
@variant='dark'
@onClick={{this.handleButtonClick}}
@onClick={{this.signup}}
@test='signup'
@disabled={{if this.isSignupButtonDisabled true false}}
@disabled={{this.isSignupButtonDisabled}}
@type='button'
/>
</div>
36 changes: 23 additions & 13 deletions app/components/signup-steps/step-one.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { APPS } from '../../constants/urls';
import { toastNotificationTimeoutOptions } from '../../constants/toast-notification';
export default class SignupStepsStepOneComponent extends Component {
@service toast;
@service onboarding;
@tracked data = { firstname: '', lastname: '', username: '', role: '' };
@tracked isSignupButtonDisabled = true;
@tracked isValid = true;
Expand All @@ -35,17 +36,11 @@ export default class SignupStepsStepOneComponent extends Component {
return (
!!this.data.firstname &&
!!this.data.lastname &&
!!this.data.username &&
!!this.data.role &&
this.mavenRoleConfirm
);
} else {
return (
!!this.data.firstname &&
!!this.data.lastname &&
!!this.data.username &&
!!this.data.role
);
return !!this.data.firstname && !!this.data.lastname && !!this.data.role;
}
}

Expand Down Expand Up @@ -118,13 +113,28 @@ export default class SignupStepsStepOneComponent extends Component {
}
}

@action handleButtonClick() {
this.isSignupButtonDisabled = true;
this.signup();
localStorage.setItem('role', this.data.role);
}

@action async signup() {
const { username } = await this.onboarding.generateUsername(
this.data.firstname,
this.data.lastname,
);

let dataToUpdate = {
username,
first_name: this.data.firstname,
last_name: this.data.lastname,
};

if (this.data.role !== 'Developer') {
dataToUpdate.roles = {
maven: this.data.role === 'Maven',
designer: this.data.role === 'Designer',
productmanager: this.data.role === 'Product Manager',
};
}

await this.onboarding.signup(dataToUpdate);
localStorage.setItem('role', this.data.role);
this.args.incrementStep();
}
}
4 changes: 4 additions & 0 deletions app/constants/error-messages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const ERROR_MESSAGES = {
somethingWentWrong: 'Something went wrong!',
usernameGeneration: 'Username cannot be generated',
};
2 changes: 1 addition & 1 deletion app/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default class UserModel extends Model {
@attr first_name;
@attr last_name;
@attr username;
@attr('string', { defaultValue: 'active' }) status;
@attr('string', { defaultValue: 'onboarding' }) status;
@attr roles;
@attr yoe;
@attr picture;
Expand Down
30 changes: 30 additions & 0 deletions app/serializers/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export default class UserSerializer extends ApplicationSerializer {
};
return { error };
}

const data = payload.users.map((user) => {
const { id, ...other } = user;
return {
Expand All @@ -21,4 +22,33 @@ export default class UserSerializer extends ApplicationSerializer {
const links = { ...payload.links, first: null, last: null };
return { data, links };
}

normalizeResponse(store, primaryModelClass, payload, id, requestType) {
if (requestType === 'queryRecord' && payload.username) {
return {
data: {
id: payload.username,
type: primaryModelClass.modelName,
attributes: {
username: payload.username,
},
},
};
} else {
return super.normalizeResponse(
store,
primaryModelClass,
payload,
id,
requestType,
);
}
}

serialize() {
let json = super.serialize(...arguments);
// Remove 'id' as the user patch API does not accept it
delete json.id;
return json;
}
}
60 changes: 60 additions & 0 deletions app/services/onboarding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import Service from '@ember/service';
import { inject as service } from '@ember/service';
import { TOAST_OPTIONS } from '../constants/toast-options';
import { ERROR_MESSAGES } from '../constants/error-messages';

export default class OnboardingService extends Service {
@service store;
@service toast;

async signup(dataToUpdate) {
try {
let user = this.store.peekRecord('user', dataToUpdate.username);

if (!user) {
user = this.store.createRecord('user', {});
}

if (dataToUpdate.roles) {
user.set('roles', {
...user.get('roles'),
...dataToUpdate.roles,
});
}

user.setProperties({
first_name: dataToUpdate.first_name,
last_name: dataToUpdate.last_name,
});

await user.save();
} catch (error) {
this.toast.error(
ERROR_MESSAGES.somethingWentWrong,
'error!',
TOAST_OPTIONS,
);
}
}

async generateUsername(firstname, lastname) {
try {
const sanitizedFirstname = firstname.toLowerCase();
const sanitizedLastname = lastname.toLowerCase();
const user = await this.store.queryRecord('user', {
firstname: sanitizedFirstname,
lastname: sanitizedLastname,
dev: true,
});
if (user && user.username) {
return user;
}
} catch (err) {
this.toast.error(
ERROR_MESSAGES.usernameGeneration,
'error!',
TOAST_OPTIONS,
);
}
}
}
74 changes: 5 additions & 69 deletions tests/integration/components/signup-steps/step-one-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { module, test, skip } from 'qunit';
import { module, test } from 'qunit';
import { setupRenderingTest } from 'website-www/tests/helpers';
import { render, typeIn, select, click } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
Expand Down Expand Up @@ -47,67 +47,6 @@ module('Integration | Component | signup-steps/step-one', function (hooks) {
assert.dom('[data-test-input-field]').hasProperty('value', 'shubham');
});

test('it render disable username input field and disable Generate Username button on signupDetails page', async function (assert) {
assert.expect(19);

await render(hbs`<SignupSteps::StepOne />`);

assert
.dom('[data-test-input-field=username]')
.hasAttribute('name', 'username');
assert.dom('[data-test-input=username]').hasClass('input-box');
assert.dom('[data-test-input=username]').hasClass('input-box--btn');

assert.dom('[data-test-label=username]').hasClass('label');
assert.dom('[data-test-label=username]').hasText('Username');
assert.dom('[data-test-label=username]').hasAttribute('for', 'username');

assert.dom('[data-test-required=username]').hasClass('required');

assert.dom('[data-test-input-field=username]').hasClass('input__field');
assert.dom('[data-test-input-field=username]').hasClass('input-disable');

assert.dom('[data-test-input-field=username]').hasAttribute('required');
assert
.dom('[data-test-input-field=username]')
.hasAttribute('name', 'username');
assert.dom('[data-test-input-field=username]').hasProperty('type', 'text');
assert
.dom('[data-test-input-field=username]')
.hasAttribute('id', 'username');
assert
.dom('[data-test-input-field=username]')
.hasProperty('disabled', true);

assert.dom('[data-test-button=generateUsername]').exists();
assert
.dom('[data-test-button=generateUsername]')
.hasClass('btn-generateUsername');
assert
.dom('[data-test-button=generateUsername]')
.hasProperty('type', 'button');
assert
.dom('[data-test-button=generateUsername]')
.hasText('Generate Username');
assert
.dom('[data-test-button=generateUsername]')
.hasProperty('disabled', true);
});

test('generateUsername button is enabled when firstname and lastname input fields are not empty and valid input', async function (assert) {
assert.expect(1);
this.set('onInput', (e) => {
this.value = e.target.value;
});

await render(hbs`<SignupSteps::StepOne />`);
await typeIn('[data-test-input-field=firstname]', 'shubham');
await typeIn('[data-test-input-field=lastname]', 'sigdar');
assert
.dom('[data-test-button=generateUsername]')
.hasProperty('disabled', false);
});

test('render select your role dropdown on signup details page ', async function (assert) {
assert.expect(11);

Expand Down Expand Up @@ -140,9 +79,7 @@ module('Integration | Component | signup-steps/step-one', function (hooks) {
await typeIn('[data-test-input-field=firstname]', 'shubham_1');
await typeIn('[data-test-input-field=lastname]', 'sigdar@');
assert.dom('.error__message').exists();
assert
.dom('[data-test-button=generateUsername]')
.hasProperty('disabled', true);
assert.dom('[data-test-button=signup]').hasProperty('disabled', true);
});

test('it renders label and input checkbox when Maven role is chosen', async function (assert) {
Expand Down Expand Up @@ -180,17 +117,16 @@ module('Integration | Component | signup-steps/step-one', function (hooks) {
assert.dom('[data-test-button=signup]').hasText('Signup');
});

skip('role based button should be enabled when all required fields are filled', async function (assert) {
test('signup button should be enabled when all required fields are filled', async function (assert) {
assert.expect(1);

await render(hbs`<SignupSteps::StepOne />`);

await typeIn('[data-test-input-field=firstname]', 'shubham');
await typeIn('[data-test-input-field=lastname]', 'sigdar');
await click('[data-test-button=generateUsername]');

select('[data-test-dropdown-field]', 'Maven');
await click('[data-test-dropdown-option="Maven"]');
select('[data-test-dropdown-field]', 'Designer');
await click('[data-test-dropdown-option="Designer"]');

assert.dom('[data-test-button=signup]').hasProperty('disabled', false);
});
Expand Down
Loading

0 comments on commit f41ad60

Please sign in to comment.