Skip to content

Commit

Permalink
feat: add user status modal, controller for status
Browse files Browse the repository at this point in the history
  • Loading branch information
MayankBansal12 committed Jan 17, 2025
1 parent 4f6a3e1 commit ec59cf4
Show file tree
Hide file tree
Showing 4 changed files with 365 additions and 0 deletions.
73 changes: 73 additions & 0 deletions app/components/user-status-modal.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{{#if @showUserStateModal}}
<div class="status-modal-overlay">
<div class="status-modal" data-test-modal>
<div class="modal__inputs">
<label
class="modal__inputs--description"
for="fromDate"
data-test-label-from
>From</label>
<Input
id="fromDate"
name="fromDate"
@type="date"
min={{this.disableDatesPrior}}
@value={{this.fromDate}}
{{on "change" this.updateValue}}
data-test-date-picker-from
/>
<label
class="modal__inputs--description"
for="untilDate"
data-test-label-until
>Until</label>
<Input
id="untilDate"
name="untilDate"
@type="date"
min={{if this.fromDate this.fromDate this.disableDatesPrior}}
@value={{this.untilDate}}
{{on "change" this.updateValue}}
data-test-date-picker-until
/>

<label
class="modal__inputs--description"
for="reason"
data-test-label-reason
>Reason</label>

<textarea
id="reason"
name="reason"
class="modal__text-area"
value={{this.reason}}
{{on "input" this.handleInput}}
data-test-textarea-reason
></textarea>

</div>
<button
disabled={{this.disableSubmitButton}}
type="button"
class={{if
this.disableSubmitButton
"modal__submit--disabled"
"modal__submit"
}}
{{on "click" this.getCurrentStatusObj}}
data-test-submit-button
>
Submit
</button>
<button
type="button"
class="modal__close"
{{on "click" this.onCancelModal}}
data-test-cancel-button
>
Cancel
</button>
</div>
</div>
{{/if}}
164 changes: 164 additions & 0 deletions app/components/user-status-modal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import { toastNotificationTimeoutOptions } from '../constants/toast-notification';
import {
WARNING_MESSAGE_FOR_IDLE,
WARNING_MESSAGE_FOR_OOO,
WARNING_MESSAGE_FOR_FROM_FIELD,
WARNING_MESSAGE_FOR_UNTIL_FIELD,
USER_STATES,
WARNING_FROM_DATE_EXCEEDS_UNTIL_DATE,
THREE_DAYS_TIME_DIFFERENCE_MS,
FROM_DATE,
UNTIL_DATE,
REASON,
} from '../constants/user-status';
import { getUTCMidnightTimestampFromDate } from '../utils/date-conversion';

export default class UserStatusModalComponent extends Component {
@service toast;
@service featureFlag;
@tracked currentStatus;
@tracked fromDate = '';
@tracked untilDate = '';
@tracked reason = '';
@tracked disableSubmitButton = true;
@tracked disableDatesPrior = new Date().toJSON().slice(0, 10);
USER_STATES = USER_STATES;

@action
updateValue(event) {
const { name, value } = event.target;
if (name === FROM_DATE) {
this.fromDate = value;
} else if (name === UNTIL_DATE) {
this.untilDate = value;
} else if (name === REASON) {
this.reason = value;
}
this.checkSubmitBtnState();
}

@action
async getCurrentStatusObj() {
let from;
let until;
const isDevMode = this.featureFlag.isDevMode;
if (this.args.newStatus === USER_STATES.OOO) {
if (!this.fromDate) {
this.toast.error(
WARNING_MESSAGE_FOR_FROM_FIELD,
'',
toastNotificationTimeoutOptions,
);
return;
}
if (!this.untilDate) {
this.toast.error(
WARNING_MESSAGE_FOR_UNTIL_FIELD,
'',
toastNotificationTimeoutOptions,
);
return;
}
if (this.untilDate < this.fromDate) {
this.toast.error(
WARNING_FROM_DATE_EXCEEDS_UNTIL_DATE,
'',
toastNotificationTimeoutOptions,
);
return;
}
from = getUTCMidnightTimestampFromDate(this.fromDate);
until = getUTCMidnightTimestampFromDate(this.untilDate);
const isReasonReq = !this.checkIfFromToDatesAreClose();

if (isReasonReq && !this.reason.length) {
this.toast.error(
WARNING_MESSAGE_FOR_OOO,
'',
toastNotificationTimeoutOptions,
);
return;
}
} else if (this.args.newStatus === USER_STATES.IDLE) {
const currentDate = new Date();
const currentDateString = currentDate.toISOString().slice(0, 10);
from = getUTCMidnightTimestampFromDate(currentDateString);
if (!this.reason.length) {
this.toast.error(
WARNING_MESSAGE_FOR_IDLE,
'',
toastNotificationTimeoutOptions,
);
return;
}
}
const updatedAt = Date.now();
const newStateObj = {
updatedAt,
from,
until,
message: this.reason,
state: this.args.newStatus,
};
if (isDevMode) {
await this.args.statusUpdateDevApi(
this.fromDate,
this.untilDate,
this.reason,
);
} else {
await this.args.updateStatus({ currentStatus: newStateObj });
}
this.resetInputFields();
this.disableSubmitButton = true;
}

@action
handleInput(event) {
const { value } = event.target;
this.reason = value;
this.checkSubmitBtnState();
}

@action
checkSubmitBtnState() {
this.disableSubmitButton = true;
if (this.checkIfFromToDatesAreClose()) {
this.disableSubmitButton = false;
} else if (
this.fromDate !== '' &&
this.untilDate !== '' &&
this.reason !== ''
) {
this.disableSubmitButton = false;
}
}

@action
checkIfFromToDatesAreClose() {
if (this.fromDate && this.untilDate) {
let from = new Date(this.fromDate.replaceAll('-', ',')).getTime();
let until = new Date(this.untilDate.replaceAll('-', ',')).getTime();
const timeGap = until - from;
return timeGap <= THREE_DAYS_TIME_DIFFERENCE_MS;
}
return false;
}

@action
resetInputFields() {
this.fromDate = '';
this.untilDate = '';
this.reason = '';
}

@action
onCancelModal() {
this.resetInputFields();
this.args.toggleUserStateModal();
}
}
106 changes: 106 additions & 0 deletions app/controllers/status.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import { toastNotificationTimeoutOptions } from '../constants/toast-notification';
import { USER_STATES } from '../constants/user-status';
import { getUTCMidnightTimestampFromDate } from '../utils/date-conversion';
import { APPS } from '../constants/urls';
const BASE_URL = APPS.API_BACKEND;

export default class StatusController extends Controller {
@service featureFlag;
@service toast;
@tracked status = this.model;
@tracked isStatusUpdating = false;
@tracked showUserStateModal = false;
@tracked newStatus;

@action toggleUserStateModal() {
this.showUserStateModal = !this.showUserStateModal;
}

@action async updateStatus(newStatus) {
this.isStatusUpdating = true;
if (!('cancelOoo' in newStatus)) {
if (newStatus.currentStatus.state !== USER_STATES.ACTIVE) {
this.toggleUserStateModal();
}
}
try {
await fetch(`${BASE_URL}/users/status/self?userStatusFlag=true`, {
method: 'PATCH',
body: JSON.stringify(newStatus),
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
})
.then((response) => response.json())
.then((responseData) => {
if (responseData.data.currentStatus?.state) {
this.status = responseData.data.currentStatus.state;
this.toast.success(
'Current status updated successfully.',
'',
toastNotificationTimeoutOptions,
);
} else if (responseData.data.futureStatus?.state) {
this.toast.success(
'Future status updated successfully.',
'',
toastNotificationTimeoutOptions,
);
}
});
} catch (error) {
console.error('Error : ', error);
this.toast.error(
'Status Update failed. Something went wrong.',
'',
toastNotificationTimeoutOptions,
);
} finally {
this.isStatusUpdating = false;
}
}

@action
async statusUpdateDevApi(from, until, message) {
this.isStatusUpdating = true;
const statusRequestBody = {
type: 'OOO',
from: getUTCMidnightTimestampFromDate(from),
until: getUTCMidnightTimestampFromDate(until),
message,
state: 'PENDING',
};
try {
const response = await fetch(`${BASE_URL}/requests?dev=true`, {
method: 'POST',
body: JSON.stringify(statusRequestBody),
headers: {
'Content-Type': 'application/json',
},
credentials: 'include',
});
if (response.ok) {
const data = await response.json();
this.toast.success(data.message, '', toastNotificationTimeoutOptions);
}
} catch (error) {
this.toast.error(
'OOO status request failed. Something went wrong.',
'',
toastNotificationTimeoutOptions,
);
} finally {
this.isStatusUpdating = false;
}
}

@action changeStatus(status) {
this.newStatus = status;
this.toggleUserStateModal();
}
}
22 changes: 22 additions & 0 deletions app/templates/status.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{{page-title "User Status"}}

<div class="status-container">
<UserStatus
@status={{this.status}}
@changeStatus={{this.changeStatus}}
@isStatusUpdating={{this.isStatusUpdating}}
@updateStatus={{this.updateStatus}}
@dev={{this.isDevMode}}
@statusUpdateDevApi={{this.statusUpdateDevApi}}
/>

<UserStatusModal
@isStatusUpdating={{this.isStatusUpdating}}
@newStatus={{this.newStatus}}
@showUserStateModal={{this.showUserStateModal}}
@toggleUserStateModal={{this.toggleUserStateModal}}
@updateStatus={{this.updateStatus}}
@dev={{this.isDevMode}}
@statusUpdateDevApi={{this.statusUpdateDevApi}}
/>
</div>

0 comments on commit ec59cf4

Please sign in to comment.