From a365dcc5ba34ead16b262e68aa2b6a061985df2d Mon Sep 17 00:00:00 2001 From: Rohan Raj Gupta <78433013+rohan09-raj@users.noreply.github.com> Date: Sat, 10 Dec 2022 13:10:53 +0530 Subject: [PATCH 1/4] handles the case when user status not found in collection (#337) (#338) * handles the case when user status not found in collection * Resolves Rohan Raj comments on #337 Co-authored-by: Randhir Kumar Singh <97341921+heyrandhir@users.noreply.github.com> --- app/components/user-status.hbs | 9 +++--- app/components/user-status.js | 56 +++++++++++++++++++++++----------- app/constants/user-status.js | 7 ++++- app/routes/index.js | 12 ++++++-- 4 files changed, 57 insertions(+), 27 deletions(-) diff --git a/app/components/user-status.hbs b/app/components/user-status.hbs index 47a59d77..06f3b280 100644 --- a/app/components/user-status.hbs +++ b/app/components/user-status.hbs @@ -9,12 +9,11 @@
{{#each this.currentUserStatus as |currentStatus|}} {{#if (eq @status currentStatus.status)}} - - + {{/each}} {{/if}} {{/each}}
diff --git a/app/components/user-status.js b/app/components/user-status.js index 5529adf1..56d91b74 100644 --- a/app/components/user-status.js +++ b/app/components/user-status.js @@ -1,36 +1,56 @@ import Component from '@glimmer/component'; import { USER_STATES } from '../constants/user-status'; export default class UserStatusComponent extends Component { + ALL_FEASIBLE_STATUS = { + [USER_STATES.ACTIVE]: { + status: USER_STATES.ACTIVE, + message: 'Change your status to Active', + class: 'buttons__active', + }, + [USER_STATES.IDLE]: { + status: USER_STATES.IDLE, + message: 'Change your status to Idle', + class: 'buttons__idle', + }, + [USER_STATES.OOO]: { + status: USER_STATES.OOO, + message: 'Change your status to OOO', + class: 'buttons__ooo', + }, + }; currentUserStatus = [ { status: USER_STATES.ACTIVE, message: 'You are Active', - firstAvailableStatus: USER_STATES.IDLE, - firstStatusMessage: 'Change your status to Idle', - firstStatusClass: 'buttons__idle', - secondAvailableStatus: USER_STATES.OOO, - secondStatusMessage: 'Change your status to OOO', - secondStatusClass: 'buttons__ooo', + otherAvailableStatus: [ + this.ALL_FEASIBLE_STATUS.IDLE, + this.ALL_FEASIBLE_STATUS.OOO, + ], }, { status: USER_STATES.IDLE, message: 'You are Idle', - firstAvailableStatus: USER_STATES.ACTIVE, - firstStatusMessage: 'Change your status status to Active', - firstStatusClass: 'buttons__active', - secondAvailableStatus: USER_STATES.OOO, - secondStatusMessage: 'Change your status status to OOO', - secondStatusClass: 'buttons__ooo', + otherAvailableStatus: [ + this.ALL_FEASIBLE_STATUS.ACTIVE, + this.ALL_FEASIBLE_STATUS.OOO, + ], }, { status: USER_STATES.OOO, message: 'You are OOO', - firstAvailableStatus: USER_STATES.IDLE, - firstStatusMessage: 'Change your status status to Idle', - firstStatusClass: 'buttons__idle', - secondAvailableStatus: USER_STATES.ACTIVE, - secondStatusMessage: 'Change your status status to Active', - secondStatusClass: 'buttons__active', + otherAvailableStatus: [ + this.ALL_FEASIBLE_STATUS.ACTIVE, + this.ALL_FEASIBLE_STATUS.IDLE, + ], + }, + { + status: USER_STATES.DNE, + message: `Your Status doesn't exist`, + otherAvailableStatus: [ + this.ALL_FEASIBLE_STATUS.ACTIVE, + this.ALL_FEASIBLE_STATUS.IDLE, + this.ALL_FEASIBLE_STATUS.OOO, + ], }, ]; } diff --git a/app/constants/user-status.js b/app/constants/user-status.js index 5eb62dab..f6807bb9 100644 --- a/app/constants/user-status.js +++ b/app/constants/user-status.js @@ -4,6 +4,11 @@ export const WARNING_MESSAGE_FOR_OOO = 'The Reason Field is mandatory. Please mention the reason for going OOO.'; export const WARNING_MESSAGE_FOR_IDLE = 'The Missing Skills Field is mandatory. Please mention the skills you are lagging in.'; -export const USER_STATES = { IDLE: 'IDLE', ACTIVE: 'ACTIVE', OOO: 'OOO' }; +export const USER_STATES = { + IDLE: 'IDLE', + ACTIVE: 'ACTIVE', + OOO: 'OOO', + DNE: 'DNE', +}; export const WARNING_FROM_DATE_EXCEEDS_UNTIL_DATE = 'Until date cant lie before the From date. Please recheck the dates again.'; diff --git a/app/routes/index.js b/app/routes/index.js index 5c8276f4..a66c62d7 100644 --- a/app/routes/index.js +++ b/app/routes/index.js @@ -8,14 +8,13 @@ const API_BASE_URL = ENV.BASE_API_URL; export default class IndexRoute extends Route { @service toast; model = async () => { - const defaultStatus = USER_STATES.ACTIVE; try { const response = await fetch(`${API_BASE_URL}/users/status/self`, { credentials: 'include', }); const userData = await response.json(); - if (response.status === 200 && !userData.incompleteUserDetails) { - return userData?.data?.currentStatus?.state ?? defaultStatus; + if (response.status === 200) { + return userData?.data?.currentStatus?.state ?? USER_STATES.DNE; } else if (response.status === 401) { this.toast.error( 'You are not logged in. Please login to continue.', @@ -30,6 +29,13 @@ export default class IndexRoute extends Route { } window.open(authUrl, '_self'); }, 2000); + } else if (response.status === 404) { + this.toast.error( + `Your Status data doesn't exist yet. Please choose your status from the options below.`, + '', + toastNotificationTimeoutOptions + ); + return USER_STATES.DNE; } } catch (error) { console.error(error.message); From ccfc0a8aad949eeeeb5baf47fec3ea9c669f9240 Mon Sep 17 00:00:00 2001 From: Prakash Choudhary <34452139+prakashchoudhary07@users.noreply.github.com> Date: Sat, 11 Mar 2023 10:30:51 +0530 Subject: [PATCH 2/4] Fix: add toast service, in signup route (#371) (#372) --- app/routes/signup.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/routes/signup.js b/app/routes/signup.js index cd594e2f..9a47a457 100644 --- a/app/routes/signup.js +++ b/app/routes/signup.js @@ -9,6 +9,7 @@ import { AUTH_URL, GOTO_URL } from '../constants/url'; export default class SignupRoute extends Route { @service analytics; @service router; + @service toast; beforeModel(transition) { if (transition?.to?.queryParams?.dev === 'true') { this.analytics.trackEvent(SIGNUP.PAGE_LOADED); @@ -39,7 +40,7 @@ export default class SignupRoute extends Route { ); setTimeout(() => window.open(GOTO_URL, '_self'), 2000); } - } catch { + } catch (err) { this.toast.error( ERROR_MESSAGES.unknown, '', From 8f52558ef741236e58adc7781cadf8577aed6cc0 Mon Sep 17 00:00:00 2001 From: Aryex82 <98796547+Aryex82@users.noreply.github.com> Date: Wed, 26 Jul 2023 21:40:14 +0530 Subject: [PATCH 3/4] Dev to main sync (#459) * fix : task status fails to update to VERIFIED * fix : task status fails to update to VERIFIED --- app/components/task/holder.hbs | 1 - app/components/task/holder.js | 1 + .../components/tasks/holder-test.js | 33 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/app/components/task/holder.hbs b/app/components/task/holder.hbs index 2b96de6f..3ce2b3d7 100644 --- a/app/components/task/holder.hbs +++ b/app/components/task/holder.hbs @@ -27,7 +27,6 @@ data-test-task-status-select id='task-update' {{on 'change' this.onStatusChange}} - {{on 'change' (fn this.onUpdate @task.id)}} > {{#each this.availabletaskStatusList as |taskStatus|}} {{#if (not-eq taskStatus.key this.TASK_KEYS.ALL)}} diff --git a/app/components/task/holder.js b/app/components/task/holder.js index 1153550a..95e0b72e 100644 --- a/app/components/task/holder.js +++ b/app/components/task/holder.js @@ -95,6 +95,7 @@ export default class TasksHolderComponent extends Component { const { value } = e.target; this.status = value; this.args.onTaskChange('status', value); + this.onUpdate(this.args.task.id); } @action diff --git a/tests/integration/components/tasks/holder-test.js b/tests/integration/components/tasks/holder-test.js index b86538e9..77ad27c0 100644 --- a/tests/integration/components/tasks/holder-test.js +++ b/tests/integration/components/tasks/holder-test.js @@ -209,4 +209,37 @@ module('Integration | Component | Tasks Holder', function (hooks) { .dom('[data-test-task-status-select]') .hasValue(TASK_KEYS.IN_PROGRESS); }); + + test('Verify status change to VERIFIED', async function (assert) { + const testTask = tasksData[3]; + + testTask.status = TASK_KEYS.IN_PROGRESS; + + let onTaskUpdateCalled = 0; + + this.set('task', testTask); + this.set('onTaskUpdate', () => { + onTaskUpdateCalled++; + }); + this.set('mock', () => {}); + this.set('isLoading', false); + this.set('disabled', false); + this.set('defaultType', DEFAULT_TASK_TYPE); + + await render(hbs``); + + assert + .dom('[data-test-task-status-select]') + .hasValue(TASK_KEYS.IN_PROGRESS); + + await select('[data-test-task-status-select]', TASK_KEYS.VERIFIED); + + assert.equal(onTaskUpdateCalled, 1, 'onTaskUpdate should be called once'); + }); }); From 046c2d13c5b99857f62b8703a234bc6261c5216c Mon Sep 17 00:00:00 2001 From: Prakash Choudhary <34452139+prakashchoudhary07@users.noreply.github.com> Date: Wed, 25 Oct 2023 06:25:41 +0000 Subject: [PATCH 4/4] Dev to Main sync (#504) --- app/components/task/holder.hbs | 21 +- app/components/task/holder.js | 1 + app/components/task/latest-extension-info.hbs | 35 ++ app/components/task/latest-extension-info.js | 11 + .../task/multiple-extension-form.hbs | 143 +++++++ .../task/multiple-extension-form.js | 181 ++++++++ app/constants/user-status.js | 2 + app/styles/tasks.css | 142 ++++++- tests/fixtures/extension-requests.js | 1 + .../tasks/multiple-extension-form-test.js | 387 ++++++++++++++++++ 10 files changed, 913 insertions(+), 11 deletions(-) create mode 100644 app/components/task/latest-extension-info.hbs create mode 100644 app/components/task/latest-extension-info.js create mode 100644 app/components/task/multiple-extension-form.hbs create mode 100644 app/components/task/multiple-extension-form.js create mode 100644 tests/integration/components/tasks/multiple-extension-form-test.js diff --git a/app/components/task/holder.hbs b/app/components/task/holder.hbs index 3fd9d2f5..b6b38809 100644 --- a/app/components/task/holder.hbs +++ b/app/components/task/holder.hbs @@ -14,12 +14,21 @@
{{#if this.extensionFormOpened}} - + {{#if @dev}} + + {{else}} + + {{/if}} {{/if}} {{#if (not-eq this.status this.TASK_KEYS.VERIFIED)}} diff --git a/app/components/task/holder.js b/app/components/task/holder.js index 0673890f..4e058848 100644 --- a/app/components/task/holder.js +++ b/app/components/task/holder.js @@ -9,6 +9,7 @@ export default class TasksHolderComponent extends Component { @tracked status = this.args.task.status; @tracked extensionFormOpened = false; @tracked isLoading = false; + queryParams = ['dev']; TASK_KEYS = TASK_KEYS; availabletaskStatusList = TASK_STATUS_LIST; diff --git a/app/components/task/latest-extension-info.hbs b/app/components/task/latest-extension-info.hbs new file mode 100644 index 00000000..456a0322 --- /dev/null +++ b/app/components/task/latest-extension-info.hbs @@ -0,0 +1,35 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Request : {{#if (eq this.extension.requestNumber undefined)}} + #1 + {{else}} + #{{this.extension.requestNumber}} + {{/if}} +
Reason : {{this.extension.reason}}
Title : {{this.extension.title}}
Old Ends On : {{this.oldEndsOn}}
New Ends On : {{this.newEndsOn}}
Status : {{this.extension.status}}
+
\ No newline at end of file diff --git a/app/components/task/latest-extension-info.js b/app/components/task/latest-extension-info.js new file mode 100644 index 00000000..aeb1d4f3 --- /dev/null +++ b/app/components/task/latest-extension-info.js @@ -0,0 +1,11 @@ +import Component from '@glimmer/component'; + +export default class LatestExtensionInfoComponent extends Component { + extension = this.args.extension; + newEndsOn = this.localTime(this.extension.newEndsOn); + oldEndsOn = this.localTime(this.extension.oldEndsOn); + + localTime(time) { + return new Date(time * 1000).toLocaleString(); + } +} diff --git a/app/components/task/multiple-extension-form.hbs b/app/components/task/multiple-extension-form.hbs new file mode 100644 index 00000000..ac0ba8ed --- /dev/null +++ b/app/components/task/multiple-extension-form.hbs @@ -0,0 +1,143 @@ +
+
+
+

+ {{#if this.createExtensionRequest}} + Extension Request Form + {{else}} + Extension Details + {{/if}} +

+ {{#if this.createExtensionRequest}} +
+
+ + +

Old ETA - {{this.oldETA}}

+ + + + +
+ +
+
+ + + +
+
+
+ {{else}} +
+ {{#if this.extensionData.value}} +
+ {{#each this.extensionData.value as |extension|}} + + {{#if extension.reviewedBy}} +

Your request was + {{#if + (eq extension.status 'APPROVED') + }}approved{{else}}denied{{/if}} + by + {{extension.reviewedBy}} + {{convertDate (array extension.timestamp) end_date=0}}. +

+ {{/if}} + {{/each}} +
+ +
+ + + {{#if + (or + (eq this.previousExtensionStatus 'APPROVED') + (eq this.previousExtensionStatus 'DENIED') + ) + }} + + {{/if}} +
+ {{else if this.extensionData.isLoading}} +
+ +
+ {{else if this.extensionData.error}} +

{{this.extensionData.error}}

+
+ + +
+ {{/if}} +
+ {{/if}} +
+
\ No newline at end of file diff --git a/app/components/task/multiple-extension-form.js b/app/components/task/multiple-extension-form.js new file mode 100644 index 00000000..ffdaeb0f --- /dev/null +++ b/app/components/task/multiple-extension-form.js @@ -0,0 +1,181 @@ +import Component from '@glimmer/component'; +import { tracked } from '@glimmer/tracking'; +import { resource, use } from 'ember-resources'; +import { TrackedMap } from 'tracked-maps-and-sets'; +import ENV from 'website-my/config/environment'; +import { action } from '@ember/object'; +import { WARNING_INVALID_NEW_ETA } from '../../constants/user-status'; +import { toastNotificationTimeoutOptions } from '../../constants/toast-notification'; +import { inject as service } from '@ember/service'; + +export default class ExtensionFormComponent extends Component { + @tracked createExtensionRequest = false; + @tracked createExtensionRequestError = null; + @tracked disableExtensionRequestClose = false; + @tracked previousExtensionStatus = null; + @tracked isSubmitButtonDisabled = false; + + @service toast; + @service userState; + + oldETA = new Date(this.args.task.endsOn * 1000).toLocaleString(); + + @use load = resource(({ on }) => { + const state = new TrackedMap(); + const controller = new AbortController(); + + on.cleanup(() => controller.abort()); + (async () => { + if (this.args.task) { + state.set('isLoading', true); + try { + const response = await fetch( + `${ENV.BASE_API_URL}/extension-requests/self/?taskId=${this.args.task.id}&dev=true`, + { + credentials: 'include', + signal: controller.signal, + } + ); + if (response.status === 200) { + const data = await response.json(); + if (!data.allExtensionRequests.length) { + throw Error( + 'No extension request found for this task, want to create one?' + ); + } + state.set('value', data.allExtensionRequests); + // Set the status of the previous extension request + this.previousExtensionStatus = data.allExtensionRequests[0].status; + state.set('isLoading', false); + return; + } + this.toast.error('Something went wrong!', '', { + ...toastNotificationTimeoutOptions, + timeOut: '3000', + }); + } catch (error) { + state.set('error', error.message); + state.set('isLoading', false); + console.error(error); + this.toast.error(error.message, '', { + ...toastNotificationTimeoutOptions, + timeOut: '3000', + }); + } + } + })(); + + return state; + }); + + get extensionData() { + const result = {}; + result['isLoading'] = this.load.get('isLoading'); + result['value'] = this.load.get('value'); + result['error'] = this.load.get('error'); + return result; + } + + @action + createNewExtensionRequest() { + this.createExtensionRequest = true; + } + + @action + closeForm() { + this.createExtensionRequest = false; + } + + @action + async submitExtensionRequest(e) { + e.preventDefault(); + this.disableExtensionRequestClose = true; + this.createExtensionRequestError = null; + this.isSubmitButtonDisabled = true; + const formData = new FormData(e.target); + const extensionTime = new Date(formData.get('newEndsOn')).getTime() / 1000; + const json = {}; + formData.forEach(function (value, key) { + json[key] = value; + }); + + if (extensionTime < this.args.task.endsOn) { + this.toast.error(WARNING_INVALID_NEW_ETA, '', { + ...toastNotificationTimeoutOptions, + timeOut: '3000', + }); + this.disableExtensionRequestClose = false; + this.createExtensionRequestError = 'New ETA must be greater than Old ETA'; + return; + } + + json['newEndsOn'] = extensionTime; + //setting default values + json['taskId'] = this.args.task.id; + json['assignee'] = this.userState.get('id'); + json['oldEndsOn'] = this.args.task.endsOn; + json['status'] = 'PENDING'; + + try { + const response = await fetch( + `${ENV.BASE_API_URL}/extension-requests?dev=true`, + { + credentials: 'include', + method: 'POST', + body: JSON.stringify(json), + headers: { + 'Content-Type': 'application/json', + }, + } + ); + const data = await response.json(); + if (data.message === 'Extension Request created successfully!') { + this.disableExtensionRequestClose = false; + this.toast.success(data.message, '', { + ...toastNotificationTimeoutOptions, + timeOut: '3000', + }); + setTimeout( + (this.isSubmitButtonDisabled = true), + this.args.closeModel(), + 2000 + ); + return; + } + this.toast.error('Something went wrong!', '', { + ...toastNotificationTimeoutOptions, + timeOut: '3000', + }); + } catch (error) { + this.toast.error(error.message, '', { + ...toastNotificationTimeoutOptions, + timeOut: '3000', + }); + } finally { + this.isSubmitButtonDisabled = false; + } + } + + @action + changeExtensionRequestETA(e) { + const errorPlaceholder = document.querySelector('.error-placeholder'); + const extensionTime = new Date(e.target.value).getTime() / 1000; + if (extensionTime < this.args.task.endsOn) { + this.toast.error(WARNING_INVALID_NEW_ETA, '', { + ...toastNotificationTimeoutOptions, + timeOut: '3000', + }); + this.isSubmitButtonDisabled = true; + this.createExtensionRequestError = 'New ETA must be greater than Old ETA'; + errorPlaceholder.textContent = this.createExtensionRequestError; + errorPlaceholder.style.visibility = 'visible'; + return; + } else { + this.createExtensionRequestError = null; + this.isSubmitButtonDisabled = false; + errorPlaceholder.textContent = this.createExtensionRequestError; + errorPlaceholder.style.visibility = 'hidden'; + return; + } + } +} diff --git a/app/constants/user-status.js b/app/constants/user-status.js index 915b78a3..e3686682 100644 --- a/app/constants/user-status.js +++ b/app/constants/user-status.js @@ -11,6 +11,8 @@ export const USER_STATES = { ONBOARDING: 'ONBOARDING', DNE: 'DNE', }; +export const WARNING_INVALID_NEW_ETA = + 'The newEndsOn value cannot be smaller than the oldEndsOn value'; export const WARNING_FROM_DATE_EXCEEDS_UNTIL_DATE = 'Until date cant lie before the From date. Please recheck the dates again.'; export const THREE_DAYS_TIME_DIFFERENCE_MS = 172800000; diff --git a/app/styles/tasks.css b/app/styles/tasks.css index 7fa599d1..1d859611 100644 --- a/app/styles/tasks.css +++ b/app/styles/tasks.css @@ -420,7 +420,7 @@ padding: 18px; border-radius: 10px; background-color: var(--white); - overflow-y: scroll; + /* overflow-y: scroll; */ position: absolute; left: 30%; right: 30%; @@ -452,6 +452,7 @@ justify-content: center; align-items: center; height: 100%; + width: 100%; flex-direction: column; margin: 10px 0px; } @@ -467,7 +468,7 @@ .extension-form__content-wrapper { width: 100%; - display: flex; + /* display: flex; */ flex-direction: column; align-items: center; justify-content: center; @@ -479,7 +480,7 @@ flex-direction: column; justify-content: center; align-items: flex-start; - width: 80%; + width: 100%; } .extension-form__content form > label { font-weight: bold; @@ -494,10 +495,26 @@ color: var(--button-proceed--text); font-size: 1.2rem; border: none; + width: 100%; border-radius: 8px; + margin-top: 1rem; padding: 5px 9px; } +.multiple-extension-form__content form > button, +.multiple-extension-form__container-close { + background-color: var(--button-proceed--bg); + color: var(--button-proceed--text); + font-size: 1.2rem; + border: none; + width: 40%; + border-radius: 8px; + margin-top: 1rem; + padding: 5px 9px; + display: flex; + align-items: center; +} + .extension-form__container-close:disabled { opacity: 0.7; background-color: #888; @@ -511,8 +528,8 @@ margin: 5px 0px 15px 0px; padding: 5px; width: 100%; - border: none; - border-bottom: 1px solid var(--input-field-border); + border: 1px solid var(--input-field-border); + /* border-bottom: 1px solid var(--input-field-border); */ } .extension-info__content > table, @@ -582,3 +599,118 @@ align-items: center; } } + +.extension-info__content { + border-bottom: 1px solid var(--light-black); + margin: 10px; +} +.latest-extension-info__content table td { + white-space: normal; +} + + .multiple-extension-form__container-close { + background-color:#a70606; + color: var(--button-proceed--text); + font-size: 1.2rem; + border: none; + border-radius: 8px; + padding: 5px 9px; + width: 40%; + display: flex; + justify-content: center; + margin:0 auto; + } + +.error-message { + color: red; +} +.error-container { + align-items: center; + height: 25px; + width: 100%; +} + + +.error-placeholder { + color: red; + text-align: center; + visibility: hidden; +} + +.multiple-extension-form__create-button[disabled] { + cursor: not-allowed; + + background-color: #888; +} + +.multiple-extension-form__create-button[disabled]:hover { + background-color: #888; +} + + +.multiple-extension-form__open-button:hover , +.multiple-extension-form__create-button:hover { + background-color: #01ad01; + color: #fff; +} + +.multiple-extension-form__container-close:hover{ + background-color: #d50707; + color:#fff +} + +.multiple-extension-form__create-button { + width: 60%; +} + +.primary-button-style { + background-color: #008000; + color: var(--button-proceed--text); + font-size: 1.2rem; + width: 40%; + display: flex; + justify-content: center; + margin:0 auto; + border: none; + border-radius: 8px; + padding: 5px 9px; + transition: background-color 0.3s ease; +} + + .latest-extension-info__content th { + text-align: right; + width: 50%; + } + +.latest-extension-info__content th, td { + padding: 8px 2px; + vertical-align: top; + min-width: 50%; +} +.latest-table{ + width: 100%; +} +.latest-extension-info__content th { + text-align: right; +} +.latest-extension-info__content td { + text-align: left; + word-wrap: normal; +} +tr>th,tr>td{ + vertical-align: top; +} + +textarea { + width: 100%; + height: 50%; + overflow-y: auto; +} + +div.buttons{ + display: flex; + flex-direction:row; + min-width: 100%; + align-content: center; + justify-content: center; +} diff --git a/tests/fixtures/extension-requests.js b/tests/fixtures/extension-requests.js index 57daf0c3..241dfe34 100644 --- a/tests/fixtures/extension-requests.js +++ b/tests/fixtures/extension-requests.js @@ -9,6 +9,7 @@ const extensionRequests = [ id: 'T0S56aa3zaNsNghEPLeS', timestamp: 1673784012, assignee: 'ivinayakg', + reviewedBy: 'Joy Gupta', }, { oldEndsOn: 57658796, diff --git a/tests/integration/components/tasks/multiple-extension-form-test.js b/tests/integration/components/tasks/multiple-extension-form-test.js new file mode 100644 index 00000000..9e101ae2 --- /dev/null +++ b/tests/integration/components/tasks/multiple-extension-form-test.js @@ -0,0 +1,387 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { tasks } from 'website-my/tests/fixtures/tasks'; +import { extensionRequests } from 'website-my/tests/fixtures/extension-requests'; +import { render, click, fillIn, waitFor, settled } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; +import makeServer from 'website-my/mirage/config'; + +module('Integration | Component | Multiple Extension Form', function (hooks) { + setupRenderingTest(hooks); + let tasksData, extensionFormOpened, server; + + hooks.after(function () { + server.shutdown(); + }); + + hooks.before(function () { + tasksData = tasks; + extensionFormOpened = true; + server = makeServer({ environment: 'test' }); + extensionRequests.forEach((obj) => { + server.create('extensionRequest', obj); + }); + }); + + const toggleExtensionForm = (setter, name) => { + extensionFormOpened = !extensionFormOpened; + if (setter) { + setter(name, extensionFormOpened); + } + }; + + const closeExtensionForm = (setter, name) => () => { + extensionFormOpened = false; + if (setter) { + setter(name, false); + } + }; + + const closeExtensionModel = (setter, name) => (e) => { + if (!e) { + toggleExtensionForm(setter, name); + return; + } + e.stopPropagation(); + if (e.target.classList.contains('extension-form__container-back')) { + toggleExtensionForm(setter, name); + } + }; + + test('When Clicked /"Close Form/" button or background task extension form should unmount', async function (assert) { + this.set('task', tasksData[3]); + this.set( + 'closeExtensionModel', + closeExtensionModel(this.set, 'extensionFormOpened') + ); + this.set( + 'closeExtensionForm', + closeExtensionForm(this.set, 'extensionFormOpened') + ); + this.set('extensionFormOpened', extensionFormOpened); + await render( + hbs` + {{#if this.extensionFormOpened}} + + {{/if}}` + ); + await waitFor('[data-test-create-extension-button]'); + assert + .dom(this.element.querySelector('[data-test-create-extension-button]')) + .hasText('Request Extension'); + + await click( + this.element.querySelector('[data-test-create-extension-button]') + ); + assert.dom('[data-test-extension-form-container-close]').exists(); + const closeButton = this.element.querySelector( + '[data-test-extension-form-container-close]' + ); + assert.ok(closeButton, 'Close button should exist'); + await click(closeButton); + assert.dom(this.element.querySelector('[data-test-title]')).doesNotExist(); + }); + + test('When no extension requests found, the option to create extension request should show and then later open form', async function (assert) { + this.set('task', tasksData[3]); + this.set( + 'closeExtensionModel', + closeExtensionModel(this.set, 'extensionFormOpened') + ); + this.set( + 'closeExtensionForm', + closeExtensionForm(this.set, 'extensionFormOpened') + ); + + await render( + hbs`` + ); + await waitFor('[data-test-create-extension-button]'); + assert + .dom(this.element.querySelector('[data-test-create-extension-button]')) + .hasText('Request Extension'); + + await click( + this.element.querySelector('[data-test-create-extension-button]') + ); + assert + .dom( + this.element + .querySelector('[data-test-extension-from-content]') + .querySelector('button[type=submit]') + ) + .exists(); + }); + + test('When creating extension request, if the newEndsOn is smaller than the oldEndsOn then should throw error', async function (assert) { + this.set('task', tasksData[3]); + this.set( + 'closeExtensionModel', + closeExtensionModel(this.set, 'extensionFormOpened') + ); + this.set( + 'closeExtensionForm', + closeExtensionForm(this.set, 'extensionFormOpened') + ); + + await render( + hbs`` + ); + await waitFor('[data-test-create-extension-button]'); + assert + .dom(this.element.querySelector('[data-test-create-extension-button]')) + .hasText('Create an extension request'); + + await click( + this.element.querySelector('[data-test-create-extension-button]') + ); + assert + .dom( + this.element + .querySelector('[data-test-extension-from-content]') + .querySelector('button[type=submit]') + ) + .exists(); + + await fillIn( + '[data-test-extension-form-newEndsOn-input]', + '2021-09-09T09:45' + ); + assert + .dom(this.element.querySelector('[data-test-extension-from-error]')) + .hasText( + 'Error: The newEndsOn value cannot be smaller than the oldEndsOn value' + ); + + await settled(); + // if filled valid time then remove the error + await fillIn( + '[data-test-extension-form-newEndsOn-input]', + '2024-09-09T09:45' + ); + assert + .dom(this.element.querySelector('[data-test-extension-from-error]')) + .doesNotExist(); + }); + + test('When no extension requests found, we should be able to create one', async function (assert) { + this.set('task', tasksData[3]); + this.set( + 'closeExtensionModel', + closeExtensionModel(this.set, 'extensionFormOpened') + ); + this.set( + 'closeExtensionForm', + closeExtensionForm(this.set, 'extensionFormOpened') + ); + + await render( + hbs`` + ); + await waitFor('[data-test-create-extension-button]'); + assert + .dom(this.element.querySelector('[data-test-create-extension-button]')) + .hasText('Create an extension request'); + + await click( + this.element.querySelector('[data-test-create-extension-button]') + ); + assert + .dom( + this.element + .querySelector('[data-test-extension-from-content]') + .querySelector('button[type=submit]') + ) + .exists(); + + //create extension request + await fillIn('[data-test-extension-form-reason-input]', 'Testing'); + await fillIn( + '[data-test-extension-form-newEndsOn-input]', + '2030-12-31T02:43' + ); + await fillIn('[data-test-extension-form-title-input]', 'TestingAgain'); + await click(this.element.querySelector('button[type=submit]')); + + // rendering the component again to check the new data + await render( + hbs`` + ); + await waitFor('[data-test-extension-info-content]'); + assert + .dom(this.element.querySelector('[data-test-extension-info-content]')) + .containsText('Testing') + .containsText('TestingAgain') + .containsText('PENDING') + .containsText('1'); + }); + + test('When previous extension request is approved, the button to create extension request should be there', async function (assert) { + let extensionRequestData = extensionRequests[0]; + this.set('task', tasksData[0]); + this.set('previousExtensionStatus', extensionRequestData.status); + this.set( + 'closeExtensionModel', + closeExtensionModel(this.set, 'extensionFormOpened') + ); + this.set( + 'closeExtensionForm', + closeExtensionForm(this.set, 'extensionFormOpened') + ); + + await render( + hbs` + }` + ); + await waitFor('[data-test-extension-info-content]'); + assert + .dom(this.element.querySelector('[data-test-extension-info-content]')) + .containsText(extensionRequestData['title']) + .containsText(extensionRequestData['reason']) + .containsText(extensionRequestData['status']); + // Assert the initial state + if (['APPROVED', 'DENIED'].includes(this.previousExtensionStatus)) { + assert.dom('button[data-test-create-another-extension]').exists(); + + // Trigger the action to create a new extension request + await click('button[data-test-create-another-extension]'); + + assert + .dom( + this.element + .querySelector('[data-test-extension-from-content]') + .querySelector('button[type=submit]') + ) + .exists(); + } else { + assert.dom('[data-test-create-another-extension] button').doesNotExist(); + } + }); + + test('Review log should present if extension status is either approved or denied and reviewedBy field is present', async function (assert) { + const extensionRequestData = extensionRequests[0]; + this.set('task', tasksData[0]); + this.set('value', [extensionRequestData]); + this.set('previousExtensionStatus', extensionRequestData.status); + this.set( + 'closeExtensionModel', + closeExtensionModel(this.set, 'extensionFormOpened') + ); + this.set( + 'closeExtensionForm', + closeExtensionForm(this.set, 'extensionFormOpened') + ); + + await render( + hbs` + }` + ); + await waitFor('[data-test-extension-info-content]'); + + // Assert the initial state + if (['APPROVED', 'DENIED'].includes(this.previousExtensionStatus)) { + assert + .dom(this.element.querySelector('[data-reviewed-log]')) + .containsText(extensionRequestData['reviewedBy']) + .exists(); + } else { + assert + .dom(this.element.querySelector('[data-reviewed-log]')) + .doesNotExist(); + } + }); + + test('Review log should not be present as extensionRequestData does not contains reviewedBy field', async function (assert) { + const extensionRequestData = extensionRequests[2]; + this.set('task', tasksData[2]); + this.set('value', [extensionRequestData]); + this.set('previousExtensionStatus', extensionRequestData.status); + this.set( + 'closeExtensionModel', + closeExtensionModel(this.set, 'extensionFormOpened') + ); + this.set( + 'closeExtensionForm', + closeExtensionForm(this.set, 'extensionFormOpened') + ); + + await render( + hbs` + }` + ); + await waitFor('[data-test-extension-info-content]'); + + // Assert the initial state + assert + .dom(this.element.querySelector('[data-reviewed-log]')) + .doesNotExist(); + }); + + test('When previous extension request is pending, the option to create extension request should show and then later open form', async function (assert) { + // Set up test data and conditions, such as setting this.previousExtensionStatus + let extensionRequestData = extensionRequests[1]; + this.set('task', tasksData[0]); + this.set('previousExtensionStatus', extensionRequestData.status); + + this.set( + 'closeExtensionModel', + closeExtensionModel(this.set, 'extensionFormOpened') + ); + this.set( + 'closeExtensionForm', + closeExtensionForm(this.set, 'extensionFormOpened') + ); + + await render( + hbs`` + ); + + await waitFor('[data-test-extension-info-content]'); + + // Assert the initial state + assert.dom('[data-test-extension-form-container]').doesNotExist(); // Replace with the actual selector for the component + + // Trigger the action to create a new extension request + assert.dom('[data-test-create-another-extension] button').doesNotExist(); + + // Assert the resulting state after the action + assert.dom('[data-test-extension-form]').doesNotExist(); // Replace with the actual selector for the extension form + }); +});