src/app/manage-learn/project/task-view/task-view.page.ts
selector | app-task-view |
styleUrls | ./task-view.page.scss |
templateUrl | ./task-view.page.html |
constructor(router: Router, params: ActivatedRoute, db: DbService, utils: UtilsService, toast: ToastService, translate: TranslateService, alert: AlertController, attachmentService: AttachmentService, location: Location, networkService: NetworkService, headerService: AppHeaderService, popupService: GenericPopUpService, contentService: ContentService, navigateService: NavigationService, commonUtilService: CommonUtilService, routereParams: ActivatedRoute)
|
|||||||||||||||||||||||||||||||||||||||||||||||||||
Parameters :
|
Public addSubtask |
addSubtask()
|
Returns :
void
|
Async askPermissionToDelete | ||||||
askPermissionToDelete(subtask, type)
|
||||||
Parameters :
Returns :
any
|
checkDisabled |
checkDisabled()
|
Returns :
boolean
|
closemarkTaskAsCompleted |
closemarkTaskAsCompleted()
|
Returns :
void
|
delete | ||||
delete(data)
|
||||
Parameters :
Returns :
void
|
doAction |
doAction()
|
Returns :
void
|
Async edit | ||||||||||||||||||||
edit(what, placeholder: string, subtask?, subTaskIndex?)
|
||||||||||||||||||||
Parameters :
Returns :
any
|
enableTaskMarkButton |
enableTaskMarkButton()
|
Returns :
void
|
getSubtasksCount | ||||
getSubtasksCount(task)
|
||||
Parameters :
Returns :
any
|
getTask |
getTask()
|
Returns :
void
|
insertAttachment |
insertAttachment()
|
Returns :
void
|
ionViewWillEnter |
ionViewWillEnter()
|
Returns :
void
|
openAction |
openAction()
|
Returns :
void
|
openBodh | ||||
openBodh(link)
|
||||
Parameters :
Returns :
void
|
Async openEditModal | ||||||||||||
openEditModal(what, name, placeholder, subtask, subTaskIndex)
|
||||||||||||
Parameters :
Returns :
any
|
openResources | ||||
openResources(task)
|
||||
Parameters :
Returns :
void
|
prepareSubTaskMeta |
prepareSubTaskMeta()
|
Returns :
void
|
saveChanges |
saveChanges()
|
Returns :
void
|
saveSubTaskChanges | ||||||
saveSubTaskChanges(subtask, index)
|
||||||
Parameters :
Returns :
void
|
selectedStatus | ||||
selectedStatus(event)
|
||||
Parameters :
Returns :
void
|
selectedTaskStatus | ||||
selectedTaskStatus(event)
|
||||
Parameters :
Returns :
void
|
setDate |
setDate()
|
Returns :
void
|
setTaskEndDate |
setTaskEndDate()
|
Returns :
void
|
toEdit | ||||||
toEdit(type, copyOfString)
|
||||||
Parameters :
Returns :
void
|
update | ||||
update(goBack?)
|
||||
Parameters :
Returns :
void
|
attachments |
Type : []
|
Default value : []
|
copyOfSelectEditField |
copyOfTaskDetails |
currentYear |
Default value : new Date().getFullYear()
|
editField |
enableMarkButton |
Type : boolean
|
Default value : false
|
headerConfig |
Type : object
|
Default value : {
showHeader: true,
showBurgerMenu: false,
actionButtons: []
}
|
newSubtask |
Type : any
|
Default value : {}
|
parameters |
project |
projectCopy |
showAttachments |
Type : boolean
|
Default value : false
|
stateData |
statuses |
Default value : statuses
|
sTime |
Decorators :
@ViewChild('dateTime', {static: false})
|
subTaskCount |
Type : number
|
Default value : 0
|
task |
viewOnlyMode |
Type : boolean
|
Default value : false
|
import { Component, ViewChild, Inject } from "@angular/core";
import { Router, ActivatedRoute } from "@angular/router";
import * as _ from "underscore";
import { TranslateService } from "@ngx-translate/core";
import { AlertController } from "@ionic/angular";
import { Location } from "@angular/common";
import { statuses,statusType } from "../../core/constants/statuses.constant";
import { UtilsService } from "../../core/services/utils.service";
import { NetworkService } from "../../core/services/network.service";
import { AppHeaderService, CommonUtilService } from "@app/services";
import { DbService } from "../../core/services/db.service";
import { AttachmentService, ToastService } from "../../core";
import { GenericPopUpService } from '../../shared';
import { ContentDetailRequest, Content, ContentService } from 'sunbird-sdk';
import { NavigationService } from '@app/services/navigation-handler.service';
import { RouterLinks } from "@app/app/app.constant";
var environment = {
db: {
projects: "project.db",
categories: "categories.db",
},
deepLinkAppsUrl: ''
};
@Component({
selector: "app-task-view",
templateUrl: "./task-view.page.html",
styleUrls: ["./task-view.page.scss"],
})
export class TaskViewPage {
parameters;
@ViewChild("dateTime", { static: false }) sTime;
editField;
task;
project;
copyOfTaskDetails;
attachments = [];
showAttachments: boolean = false;
enableMarkButton: boolean = false;
subTaskCount: number = 0;
newSubtask: any = {};
currentYear = new Date().getFullYear();
statuses = statuses;
projectCopy;
copyOfSelectEditField;
headerConfig = {
showHeader: true,
showBurgerMenu: false,
actionButtons: []
};
viewOnlyMode: boolean = false;
stateData;
constructor(
private router: Router,
private params: ActivatedRoute,
private db: DbService,
private utils: UtilsService,
private toast: ToastService,
private translate: TranslateService,
private alert: AlertController,
private attachmentService: AttachmentService,
private location: Location,
private networkService: NetworkService,
private headerService: AppHeaderService,
private popupService: GenericPopUpService,
@Inject('CONTENT_SERVICE') private contentService: ContentService,
private navigateService: NavigationService,
private commonUtilService: CommonUtilService,
private routereParams: ActivatedRoute
// private openResourceSrvc: OpenResourcesService
) {
this.saveChanges = _.debounce(this.saveChanges, 800);
this.saveSubTaskChanges = _.debounce(this.saveSubTaskChanges, 800);
routereParams.queryParams.subscribe(params => {
this.viewOnlyMode = (params.viewOnlyMode === 'true');
})
params.params.subscribe((parameters) => {
this.parameters = parameters;
this.getTask();
this.prepareSubTaskMeta();
});
this.stateData = this.router.getCurrentNavigation().extras.state;
}
ionViewWillEnter() {
this.headerConfig = this.headerService.getDefaultPageConfig();
this.headerConfig.actionButtons = [];
this.headerConfig.showHeader = true;
this.headerConfig.showBurgerMenu = false;
this.headerService.updatePageConfig(this.headerConfig);
}
prepareSubTaskMeta() {
this.newSubtask = JSON.parse(JSON.stringify(this.utils.getMetaData("subTask")));
}
getTask() {
this.db.query({ _id: this.parameters.id }).then(
(success) => {
if(success?.docs.length){
this.project = success.docs[0]
} else {
this.viewOnlyMode = true;
this.project = this.stateData.projectDetails;
}
// this.project = success.docs.length ? success.docs[0] : success.docs;
this.projectCopy = JSON.parse(JSON.stringify(this.project));
let task = _.findIndex(this.projectCopy.tasks, (item) => {
return item._id == this.parameters.taskId;
});
task > -1 ? (this.task = this.project.tasks[task]) : this.toast.showMessage("FRMELEMNTS_MSG_NO_TASK_FOUND", "danger");
this.enableMarkButton = this.task.status === 'completed' ? true : false;
this.copyOfTaskDetails = JSON.stringify(this.task);
this.attachments = [];
this.getSubtasksCount(this.task).then((data: number) => {
this.subTaskCount = data;
});
},
(error) => { }
);
}
selectedStatus(event) {
this.enableTaskMarkButton();
}
selectedTaskStatus(event) {
this.task.status == 'completed' ? this.enableMarkButton = true : this.enableMarkButton = false;
if (this.task.status == 'completed' && this.task.children && this.task.children.length) {
this.task.children.forEach(element => {
element.status = 'completed';
});
}
this.enableTaskMarkButton();
}
setDate() {
this.update();
}
setTaskEndDate() {
this.sTime.open();
}
public addSubtask() {
if (this.newSubtask.name) {
this.newSubtask.isDeletable = true;
!this.task.children ? (this.task.children = []) : "";
this.task.children.push(this.newSubtask);
this.enableTaskMarkButton();
}
}
toEdit(type, copyOfString) {
this.editField = type;
this.copyOfSelectEditField = copyOfString;
}
saveChanges() {
if (this.task.name) {
this.editField = "";
this.update();
} else {
this.task.name = this.copyOfSelectEditField;
this.toast.showMessage("FRMELEMNTS_MSG_REQUIRED_FIELDS", "danger");
}
}
saveSubTaskChanges(subtask, index) {
if (subtask.name) {
this.editField = ""; // removed as it closing the edit field as one letter is entered
this.update();
} else {
this.task.children[index].name = this.copyOfSelectEditField;
this.toast.showMessage("FRMELEMNTS_MSG_REQUIRED_FIELDS", "danger");
}
}
update(goBack?) {
if (this.task.name) {
if (!this.task.isEdit) {
this.task.isEdit = this.copyOfTaskDetails === JSON.stringify(this.task) ? false : true;
this.project.isEdit = this.task.isEdit ? true : this.project.isEdit;
}
if (JSON.stringify(this.copyOfTaskDetails) !== JSON.stringify(this.task)) {
this.project.isEdit = true;
this.project.status = this.project.status ? this.project.status : statusType.notStarted;
this.project.status = this.project.status == statusType.notStarted ? statusType.inProgress:this.project.status;
}
const isProjectEdit = _.filter(this.project.tasks, (eachTask) => {
return eachTask.isEdit;
});
this.project.isEdit = isProjectEdit.length ? true : this.project.isEdit;
this.project = this.utils.setStatusForProject(this.project);
this.db
.update(this.project)
.then((success) => {
this.project._rev = success.rev;
this.prepareSubTaskMeta();
this.attachments = [];
this.toast.showMessage('FRMELEMNTS_MSG_YOUR_CHANGES_ARE_SAVED', 'success');
goBack ? this.location.back() : "";
})
} else {
this.toast.showMessage("FRMELEMNTS_MSG_REQUIRED_FIELDS", "danger");
}
}
openResources(task) {
if (task && task.learningResources && task.learningResources.length === 1) {
let link = task.learningResources[0].link;
this.openBodh(link);
return;
}
if (task) {
this.router.navigate(["/project/learning-resources", this.project._id, task._id]);
} else {
this.router.navigate(["/project/learning-resources", this.project._id]);
}
}
openBodh(link) {
if(this.commonUtilService.networkInfo.isNetworkAvailable){
const id = link.split('/').pop();
const req: ContentDetailRequest = {
contentId: id,
attachFeedback: false,
attachContentAccess: false,
emitUpdateIfAny: false
};
this.contentService.getContentDetails(req).toPromise()
.then(async (data: Content) => {
this.navigateService.navigateToDetailPage(data, { content: data });
});
} else {
this.toast.showMessage('FRMELEMNTS_MSG_OFFLINE_SHARE_PROJECT', 'danger');
}
}
delete(data) {
data.isDeleted = true;
this.enableTaskMarkButton();
}
// task and project delete permission.
async askPermissionToDelete(subtask, type) {
let data;
this.translate.get(["FRMELEMNTS_LBL_DELETE_CONFIRMATION", "NO", "YES"]).subscribe((text) => {
data = text;
});
const alert = await this.alert.create({
message: data["FRMELEMNTS_LBL_DELETE_CONFIRMATION"],
cssClass: 'background-theme-color',
buttons: [
{
text: data["NO"],
role: "cancel",
cssClass: "secondary",
handler: (blah) => { },
},
{
text: data["YES"],
handler: () => {
this.delete(subtask);
},
},
],
});
await alert.present();
}
getSubtasksCount(task) {
return new Promise(function (resolve) {
let count = 0;
if (task.children && task.children.length) {
task.children.forEach((subtask) => {
if (!subtask.isDeleted) {
count = count + 1;
}
});
resolve(count);
} else {
resolve(null);
}
});
}
enableTaskMarkButton() {
this.getSubtasksCount(this.task).then((count: number) => {
this.subTaskCount = count;
if (count) {
let inProgress = 0;
let completed = 0;
if (this.task.children.length) {
this.task.children.forEach((child) => {
if (!child.isDeleted) {
if (child.status == "inProgress") {
inProgress = inProgress + 1;
} else if (child.status == "completed") {
completed = completed + 1;
}
}
});
}
if (count === completed) {
this.task.status = "completed";
} else if (inProgress > 0) {
this.task.status = "inProgress";
}
this.task.status == "completed" ? (this.enableMarkButton = true) : (this.enableMarkButton = false);
} else {
this.task.status == "completed" ? (this.enableMarkButton = true) : (this.enableMarkButton = false);
}
this.update();
});
}
closemarkTaskAsCompleted(){
this.showAttachments = false;
}
insertAttachment() {
this.showAttachments = false;
!this.task.attachments ? (this.task.attachments = []) : "";
if (this.attachments && this.attachments.length) {
this.attachments.forEach((element) => {
this.task.attachments.push(element);
});
}
this.update("goBack");
}
openAction() {
this.attachmentService.selectImage().then((data) => {
data.data ? this.attachments.push(data.data) : "";
});
}
doAction() {
this.popupService.showPPPForProjectPopUp('FRMELEMNTS_LBL_EVIDENCES_CONTENT_POLICY', 'FRMELEMNTS_LBL_EVIDENCES_CONTENT_POLICY_TEXT', 'FRMELEMNTS_LBL_EVIDENCES_CONTENT_POLICY_LABEL', 'FRMELEMNTS_LBL_UPLOAD_EVIDENCES', 'https://diksha.gov.in/term-of-use.html', 'contentPolicy').then((data: any) => {
if (data.isClicked) {
data.isChecked ? this.router.navigate([`${RouterLinks.PROJECT}/${RouterLinks.ADD_FILE}`,this.parameters.id],{queryParams:{taskId:this.task._id}}) : this.toast.showMessage('FRMELEMNTS_MSG_EVIDENCES_CONTENT_POLICY_REJECT', 'danger');
}
})
}
async edit(what, placeholder = "", subtask?, subTaskIndex?) {
let name;
switch (what) {
case 'task':
if(this.task.isDeletable){
name = "Edit Task";
this.openEditModal(what,name,placeholder,subtask,subTaskIndex);
}
break
case 'subtask':
if(subtask.isDeletable){
name = "Edit Subtask"
this.openEditModal(what,name,placeholder,subtask,subTaskIndex);
}
break
}
}
async openEditModal(what,name,placeholder,subtask,subTaskIndex){
const alert = await this.alert.create({
cssClass: "central-alert",
header: name,
// message: "Message <strong>text</strong>!!!",
inputs: [
{
name: "field",
type: "text",
value: placeholder
},
],
buttons: [
{
text: "Cancel",
role: "cancel",
cssClass: "secondary",
handler: (blah) => { },
},
{
text: "Save",
handler: (data) => {
if (data.field == "" && what != "assignName") {
this.toast.showMessage("FRMELEMNTS_MSG_REQUIRED_FIELDS", "danger");
return;
}
if (what == "subtask") {
subtask.name = data.field;
this.saveSubTaskChanges(subtask, subTaskIndex);
} else if (what == "assignName") {
this.task.assignee = data.field;
this.saveChanges()
} else {
this.task.name = data.field;
this.update();
}
},
},
],
});
await alert.present();
alert.present().then(() => {
const firstInput: any = document.querySelector("ion-alert input");
firstInput.focus();
return;
});
}
checkDisabled() {
if (this.task.type == "assessment" || this.task.type == "observation") {
return this.subTaskCount == 0 || this.subTaskCount == undefined || this.subTaskCount > 0; // disabled all the time
} else {
return this.subTaskCount > 0;
}
}
}
<ion-content *ngIf="task" class="ion-padding background-theme-color">
<div [ngClass]="{'disablePage' : viewOnlyMode}">
<div class="heading-name" (click)="edit('task',task?.name)">
<h4 *ngIf="editField != 'name'">{{task?.name}}</h4>
<ion-icon name="create" color="primary" class="iconAdj" *ngIf="task.isDeletable"> </ion-icon>
</div>
<ion-row>
<ion-col size="3">
<img src="assets/imgs/timetable.png" class="filter-icon-calendar" (click)="setTaskEndDate()" alt=""/>
</ion-col>
<ion-col size="9">
<ion-datetime (ionChange)="setDate()" #dateTime value="{{task?.endDate}}" display-timezone="utc"
min="{{currentYear - 2}}" max="{{currentYear + 5}}" display-timezone="utc" [(ngModel)]="task.endDate">
</ion-datetime>
</ion-col>
</ion-row>
<ion-row>
<ion-col size="4" class="status-label">
<ion-label position="fixed"> {{'FRMELEMNTS_LBL_STATUS' | translate}} </ion-label>
</ion-col>
<ion-col size="8">
<ion-select [(ngModel)]="task.status" class="custom-select" [disabled]="checkDisabled()" [interfaceOptions]="{
cssClass: 'select-box',
animated: false
}" placeholder="{{'FRMELEMNTS_LBL_SELECT_STATUS_PLACEHOLDER' | translate}}"
(ionChange)="selectedTaskStatus($event)">
<ion-select-option *ngFor="let status of statuses" value="{{status.title}}"
selected="status.title === task.status">{{status.title | camelToTitle}}</ion-select-option>
</ion-select>
</ion-col>
</ion-row>
<div class="subtask-form" *ngIf="task?.type !='observation' && task?.type != 'assessment'">
<h4>{{'FRMELEMNTS_LBL_SUBTASKS' | translate}}</h4>
<ion-row>
<ion-col size="3"> <img src="assets/imgs/subdirectory_arrow.png" class="filter-icon arrow-image" alt=""/> </ion-col>
<ion-col size="9">
<ion-item>
<ion-input type="text" placeholder="{{'FRMELEMNTS_LBL_ADD_SUBTASK_PALCEHOLDER' | translate}}"
[(ngModel)]="newSubtask.name" autocapitalize='on'>
</ion-input>
</ion-item>
<ion-button (click)="addSubtask()" [ngClass]="{'btn-disabled': !newSubtask.name}"
class="custom-btn-txt-transform-none">
{{'FRMELEMNTS_LBL_ADD_SUBTASK' | translate}} </ion-button>
</ion-col>
</ion-row>
</div>
<div class="subtask-box " *ngFor="let subtask of task?.children; let subTaskIndex = index">
<ion-card class="ion-padding" style="background: #ffffff;" *ngIf="!subtask.isDeleted">
<ion-row>
<ion-col size="1">
<ion-icon name="radio-button-off" color="primary"></ion-icon>
</ion-col>
<ion-col size="10" class="subtask-title" (click)="edit('subtask',subtask.name,subtask,subTaskIndex)"
*ngIf="editField != 'subtaskName'">
{{subtask.name}}
</ion-col>
<ion-col size="1" style="margin: auto; text-align: center" *ngIf="subtask.isDeletable">
<img src="assets/imgs/Delete.png" class="filter-icon" style="width: 1.25rem"
(click)="askPermissionToDelete(subtask,'subtask')" alt=""/>
</ion-col>
</ion-row>
<ion-row>
<ion-col size="6">
<ion-item class="ion-date-time" lines="none">
<img src="assets/imgs/timetable.png" class="filter-icon subtask-date-picker" alt=""/>
<ion-datetime value="{{subtask?.endDate}}" (ionChange)="setDate()" [(ngModel)]="subtask.endDate"
displayFormat="DD/MM/YYYY" min="{{currentYear - 2}}" max="{{currentYear + 5}}" display-timezone="utc">
</ion-datetime>
</ion-item>
</ion-col>
<ion-col size="6">
<ion-select [(ngModel)]="subtask.status" class="custom-select"
placeholder="{{'FRMELEMNTS_LBL_SELECT_STATUS_PLACEHOLDER' | translate}}"
(ionChange)="selectedStatus($event)" [interfaceOptions]="{
cssClass: 'select-box',
animated: false
}">
<ion-select-option *ngFor="let status of statuses" value="{{status.title}}"
selected="status.title === subtask.status">{{status.title | camelToTitle}}</ion-select-option>
</ion-select>
</ion-col>
</ion-row>
</ion-card>
</div>
<ion-button expand="block" shape="round" (click)="doAction()"
class="custom-btn-txt-transform-none" *ngIf="!task?.learningResources?.length">
{{'FRMELEMNTS_LBL_ADD_FILES' | translate}}
</ion-button>
<ion-row *ngIf="task?.learningResources?.length">
<ion-col size="5">
<ion-button class="roundedButton custom-btn-txt-transform-none" expand="block" shape="round" (click)="openResources(task)">
{{'FRMELEMNTS_LBL_VIEW_RESOURCES' | translate}}
</ion-button>
</ion-col>
<ion-col size="7">
<ion-button class="roundedButton custom-btn-txt-transform-none" expand="block"
shape="round" (click)="doAction()">
{{'FRMELEMNTS_LBL_ADD_FILES' | translate}}
</ion-button>
</ion-col>
</ion-row>
</div>
</ion-content>
./task-view.page.scss
@import "src/assets/styles/_variables.scss";
.heading-name{
display: flex;
justify-content: space-between;
align-items: center;
h4{
word-break: break-all;
max-width: 92%;
}
}
.filter-icon-calendar {
width: 3rem;
height: 3rem;
}
.status-label {
margin: auto;
font-size: 1.25rem;
font-weight: 500;
}
.btn-disabled{
--background: #999999 !important;
--border-color: #999999 !important;
}
.subtask-form {
margin: 0px;
padding: 5px;
.arrow-image {
width: 2.438rem;
margin-top: 5px;
}
ion-item {
font-size: 0.813rem;
}
ion-button {
text-transform: none;
}
}
ion-button {
font-size: 0.875rem;
height: 1.813rem;
}
.subtask-box {
ion-icon {
color: #{$blue};
}
.subtask-title {
font-family: 'SourceSansPro-Bold' !important;
font-weight: 600;
}
ion-row,
ion-col {
margin: 0px;
padding: 0px;
}
}
.custom-popup {
position: fixed;
z-index: 9999;
width: 100%;
height: 100%;
overflow: auto;
background: #a9a9a966;
display: flex;
.border-radius {
border-radius: 1em;
}
.pop-container {
margin: auto;
width: 80%;
box-shadow: 0px 1px 4px 1px #5a6779;
background: var(--app-primary-background);
padding: 10px;
.pop-msg {
.close-attach-popup{
float: right;
text-align: right;
font-size: 1.5rem;
margin-top: -15px;
}
ion-textarea {
background: #fff !important;
border-radius: 0px !important;
}
}
}
}
.roundedButton {
font-size: 0.75rem;
}
.subtask-date-picker{
max-width: 1.563rem;
margin-right: 5px;
}
.assignee {
font-weight: normal;
margin-left: 20px;
font-size: 1rem;
}
.iconAdj {
font-size: 1.25rem;
}
.disablePage {
pointer-events: none;
opacity: 0.7;
}