-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add user status modal, controller for status
- Loading branch information
1 parent
4f6a3e1
commit ec59cf4
Showing
4 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> |