merge chat

This commit is contained in:
Peter Maquiran
2024-09-13 12:27:39 +01:00
471 changed files with 17419 additions and 53900 deletions
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ChatDebuggingPage } from './chat-debugging.page';
const routes: Routes = [
{
path: '',
component: ChatDebuggingPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ChatDebuggingPageRoutingModule {}
@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { ChatDebuggingPageRoutingModule } from './chat-debugging-routing.module';
import { ChatDebuggingPage } from './chat-debugging.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
ChatDebuggingPageRoutingModule
],
declarations: [ChatDebuggingPage]
})
export class ChatDebuggingPageModule {}
@@ -0,0 +1,9 @@
<!-- <ion-content>
<ul>
<li>Chat login</li>
<li>Chat user list {{ ChatSystemService.users | json }}</li>
</ul>
<ul>
<li *ngFor="let room of ChatSystemService._dm">chat Name: {{room.name}}; subcribe: {{room.status.receive.message}}; </li>
</ul>
</ion-content> -->
@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { ChatDebuggingPage } from './chat-debugging.page';
describe('ChatDebuggingPage', () => {
let component: ChatDebuggingPage;
let fixture: ComponentFixture<ChatDebuggingPage>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ ChatDebuggingPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(ChatDebuggingPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,17 @@
import { Component, OnInit } from '@angular/core';
// import { ChatSystemService } from 'src/app/services/chat/chat-system.service';
@Component({
selector: 'app-chat-debugging',
templateUrl: './chat-debugging.page.html',
styleUrls: ['./chat-debugging.page.scss'],
})
export class ChatDebuggingPage implements OnInit {
constructor(
// public ChatSystemService: ChatSystemService
) { }
ngOnInit() {}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ChatMessageDebuggingPage } from './chat-message-debugging.page';
const routes: Routes = [
{
path: '',
component: ChatMessageDebuggingPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ChatMessageDebuggingPageRoutingModule {}
@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { ChatMessageDebuggingPageRoutingModule } from './chat-message-debugging-routing.module';
import { ChatMessageDebuggingPage } from './chat-message-debugging.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
ChatMessageDebuggingPageRoutingModule
],
declarations: [ChatMessageDebuggingPage]
})
export class ChatMessageDebuggingPageModule {}
@@ -0,0 +1,10 @@
<ion-header>
<ion-toolbar>
<ion-title>chatMessageDebugging</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<button (click)="loadHistory()">Load History</button>
</ion-content>
@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { ChatMessageDebuggingPage } from './chat-message-debugging.page';
describe('ChatMessageDebuggingPage', () => {
let component: ChatMessageDebuggingPage;
let fixture: ComponentFixture<ChatMessageDebuggingPage>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ ChatMessageDebuggingPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(ChatMessageDebuggingPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,29 @@
import { Component, OnInit } from '@angular/core';
import { NavParams } from '@ionic/angular';
// import { ChatSystemService } from 'src/app/services/chat/chat-system.service';
@Component({
selector: 'app-chat-message-debugging',
templateUrl: './chat-message-debugging.page.html',
styleUrls: ['./chat-message-debugging.page.scss'],
})
export class ChatMessageDebuggingPage implements OnInit {
roomId: string
constructor(
// public ChatSystemService: ChatSystemService,
private navParams: NavParams
) { }
ngOnInit() {
this.roomId = this.navParams.get('roomId')
}
loadHistory() {
// this.ChatSystemService.getDmRoom(this.roomId).loadHistory({});
}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ChatOptionsPopoverPage } from './chat-options-popover.page';
const routes: Routes = [
{
path: '',
component: ChatOptionsPopoverPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ChatOptionsPopoverPageRoutingModule {}
@@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { ChatOptionsPopoverPageRoutingModule } from './chat-options-popover-routing.module';
import { ChatOptionsPopoverPage } from './chat-options-popover.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
ChatOptionsPopoverPageRoutingModule
],
declarations: [ChatOptionsPopoverPage],
exports: [ChatOptionsPopoverPage]
})
export class ChatOptionsPopoverPageModule {}
@@ -0,0 +1,19 @@
<ion-content class="container">
<div class="arrow-right">
<button class="btn-no-color" (click)="close()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' "slot="end" class="arrow-right-icon" src='assets/images/icons-arrow-arrow-right.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="end" class="arrow-right-icon" src='assets/images/theme/gov/icons-calendar-arrow-right.svg'></ion-icon>
</button>
</div>
<div class="buttons">
<button (click)="takePicture()" full class="btn-ok" shape="round" >Tirar Fotografia</button>
<button (click)="addFile()" class="btn-ok" shape="round" >Anexar Documento</button>
<button (click)="anexarFoto()" full class="btn-ok" shape="round" >Anexar Fotografia</button>
<button (click)="addDocGestaoDocumental()" class="btn-ok" shape="round" >Gestão Documental</button>
<div class="solid"></div>
<!-- <button *ngIf="p.userPermission([p.permissionList.Agenda.access]) == true " (click)="bookMeeting()" class="btn-ok" shape="round" >Novo Evento</button> -->
<button (click)="close()" full class="btn-cancel" shape="round" >Cancelar</button>
</div>
</ion-content>
@@ -0,0 +1,50 @@
@import '~src/function.scss';
.container{
--padding-top:20px !important;
--padding-bottom:20px !important;
--padding-start:20px !important;
--padding-end:20px !important;
}
.arrow-right{
display: none;
margin-bottom: 20px;
.arrow-right-icon{
width: 37px;
float: right;
font-size: rem(35);
overflow: hidden;
}
}
.buttons{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
.btn-ok, .btn-cancel, .btn-delete{
margin-bottom: 10px !important;
}
}
.solid {
display: none;
width: 90%;
border-top: 1px solid #bbb;
margin: 0 auto !important;
margin-bottom: 10px;
}
@media only screen and (min-width: 1024px) {
.arrow-right{
display: flex;
justify-content: flex-end;
}
.btn-cancel{
display: none;
}
.btn-ok{
width: 100% !important;
}
.mobile-only{
display: none !important;
}
}
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { ChatOptionsPopoverPage } from './chat-options-popover.page';
describe('ChatOptionsPopoverPage', () => {
let component: ChatOptionsPopoverPage;
let fixture: ComponentFixture<ChatOptionsPopoverPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ChatOptionsPopoverPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(ChatOptionsPopoverPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,133 @@
import { Component, OnInit } from '@angular/core';
import { ModalController, NavParams, PopoverController } from '@ionic/angular';
import { EventPerson } from 'src/app/models/eventperson.model';
import { SearchList } from 'src/app/models/search-document';
import { NewEventPage } from 'src/app/pages/agenda/new-event/new-event.page';
import { SearchPage } from 'src/app/pages/search/search.page';
import { environment } from 'src/environments/environment';
import { ThemeService } from 'src/app/services/theme.service'
import { PermissionService } from 'src/app/services/permission.service';
@Component({
selector: 'app-chat-options-popover',
templateUrl: './chat-options-popover.page.html',
styleUrls: ['./chat-options-popover.page.scss'],
})
export class ChatOptionsPopoverPage implements OnInit {
documents:SearchList[] = [];
members: any;
attendees: EventPerson[] = [];
constructor(
private popoverController: PopoverController,
private modalController: ModalController,
private navParams: NavParams,
public ThemeService: ThemeService,
public p: PermissionService,
) {
this.members = this.navParams.get('members');
if(this.members) {
this.attendees = this.navParams.get('members').map((val)=>{
return {
Name: val.name,
EmailAddress: val.username+"@"+environment.domain,
IsRequired: "true",
}
});
}
}
ngOnInit() {
}
takePicture(){
if( window.innerWidth < 701){
this.popoverController.dismiss('take-picture');
}
else{
this.modalController.dismiss('take-picture');
}
}
addFile(){
if( window.innerWidth < 701){
this.popoverController.dismiss('add-document');
}
else{
this.modalController.dismiss('add-document');
}
}
anexarFoto(){
if( window.innerWidth < 701){
this.popoverController.dismiss('add-picture');
}
else{
this.modalController.dismiss('add-picture');
}
}
addDocGestaoDocumental(){
if( window.innerWidth < 701){
this.popoverController.dismiss('documentoGestaoDocumental');
}
else{
this.modalController.dismiss('documentoGestaoDocumental');
}
}
close(){
if( window.innerWidth < 701){
this.popoverController.dismiss();
}
else{
this.modalController.dismiss();
}
}
attachDocument(){
}
async getDoc(){
const modal = await this.modalController.create({
component: SearchPage,
cssClass: 'group-messages modal-desktop search-modal search-modal-to-desktop',
componentProps: {
type: 'AccoesPresidenciais & ArquivoDespachoElect',
select: true,
showSearchInput: true,
}
});
modal.onDidDismiss().then((res)=>{
if(res) {
const data = res.data;
this.documents.push(data.selected);
}
});
await modal.present();
}
async bookMeeting() {
if( window.innerWidth < 701){
this.popoverController.dismiss('meeting');
}
else{
this.modalController.dismiss('meeting');
}
}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ChatPopoverPage } from './chat-popover.page';
const routes: Routes = [
{
path: '',
component: ChatPopoverPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ChatPopoverPageRoutingModule {}
@@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { ChatPopoverPageRoutingModule } from './chat-popover-routing.module';
import { ChatPopoverPage } from './chat-popover.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
ChatPopoverPageRoutingModule
],
exports: [ChatPopoverPage],
declarations: [ChatPopoverPage]
})
export class ChatPopoverPageModule {}
@@ -0,0 +1,32 @@
<ion-content class="options-container">
<div class="arrow-right header-fix">
<button class="btn-no-color" (click)="close('cancel')">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="end" class="arrow-right-icon"
src='assets/images/icons-arrow-arrow-right.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="end" class="arrow-right-icon"
src='assets/images/theme/gov/icons-calendar-arrow-right.svg'></ion-icon>
</button>
</div>
<div class="buttons">
<!-- <button *ngIf="isAdmin" (click)="addUser()" class="btn-cancel" shape="round">Adicionar</button>
<button (click)="leaveGroup()" class="btn-cancel" shape="round">Sair do Grupo</button>
<button *ngIf="isAdmin" (click)="openChangeGroupName()" class="btn-cancel btn-cancel mt-10" shape="round" style="min-width: 192px;">Alterar
nome do grupo</button>
<div class="solid"></div>
<button (click)="close('cancel')" full class="btn-cancel mobile-only" shape="round">Cancelar</button>
<button *ngIf="isAdmin" (click)="deleteGroup()" class="btn-delete" shape="round">Apagar grupo</button>
-->
<ion-progress-bar type="indeterminate" *ngIf="showLoader"></ion-progress-bar>
<br *ngIf="showLoader">
<button (click)="details()" class="btn-cancel" shape="round">Detalhes</button>
<button *ngIf="isAdmin && roomType == EnumRoomType.Group" (click)="addUser()" class="btn-cancel" shape="round">Adicionar</button>
<button *ngIf="roomType == EnumRoomType.Group" (click)="leaveGroup()" class="btn-cancel" shape="round">Sair do Grupo</button>
<button *ngIf="isAdmin && roomType == EnumRoomType.Group" (click)="openChangeGroupName()" class="btn-cancel btn-cancel mt-10" shape="round" style="min-width: 192px;">Alterar
nome do grupo</button>
<button *ngIf="isAdmin && roomType == EnumRoomType.Group" (click)="setRoomOwner()" class="btn-cancel" shape="round">Adicionar admin</button>
<div class="solid"></div>
<button (click)="close('cancel')" full class="btn-cancel mobile-only" shape="round">Cancelar</button>
<button *ngIf="isAdmin && roomType == EnumRoomType.Group" (click)="deleteGroup()" class="btn-delete" shape="round">Apagar grupo</button>
</div>
</ion-content>
@@ -0,0 +1,58 @@
.options-container{
--padding-top:20px !important;
--padding-bottom:20px !important;
--padding-start:20px !important;
--padding-end:20px !important;
}
.arrow-right{
display: none;
margin-bottom: 20px;
.arrow-right-icon{
width: 37px;
float: right;
font-size: rem(35);
overflow: hidden;
}
}
.buttons{
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.solid {
display: block;
width: 90%;
border-top: 1px solid #bbb;
margin: 10px auto !important;
}
@media only screen and (min-width: 701px) {
.arrow-right{
display: flex;
justify-content: flex-end;
}
.btn-cancel{
//display: none;
width: 100% !important;
margin-bottom: 10px !important;
}
.btn-cancel:hover, .btn-delete:hover{
background-color: var(--button-hover);
color: #fff !important;
}
.btn-ok{
width: 100% !important;
}
.btn-delete{
width: 100% !important;
margin-bottom: 10px !important;
}
.solid{
display: block;
}
.mobile-only{
display: none !important;
}
}
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { ChatPopoverPage } from './chat-popover.page';
describe('ChatPopoverPage', () => {
let component: ChatPopoverPage;
let fixture: ComponentFixture<ChatPopoverPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ChatPopoverPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(ChatPopoverPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,171 @@
import { Component, OnInit } from '@angular/core';
import { ModalController, NavParams, PopoverController } from '@ionic/angular';
import { ToastService } from 'src/app/services/toast.service';
import { ThemeService } from 'src/app/services/theme.service'
import { SetRoomOwnerPage } from 'src/app/ui/chat/modal/set-room-owner/set-room-owner.page';
import { SessionStore } from 'src/app/store/session.service';
import { ZodError } from 'zod';
import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service'
import { RoomInfoPage } from '../room-info/room-info.page';
import { RoomType } from 'src/app/core/chat/entity/group';
import { isHttpResponse } from 'src/app/infra/http/http.service';
@Component({
selector: 'app-chat-popover',
templateUrl: './chat-popover.page.html',
styleUrls: ['./chat-popover.page.scss'],
})
export class ChatPopoverPage implements OnInit {
roomId:string;
room: any;
isAdmin = false;
isGroupCreated: boolean;
showLoader = false
EnumRoomType = RoomType
roomType!: RoomType
constructor(
private popoverController: PopoverController,
private modalController: ModalController,
private navParams: NavParams,
private toastService: ToastService,
public ThemeService: ThemeService,
private ChatServiceService: ChatServiceService
) {
this.roomId = this.navParams.get('roomId');
this.isAdmin = this.navParams.get('isAdmin');
this.roomType = this.navParams.get('roomType');
}
ngOnInit() {
// this.chatService.refreshtoken();
}
close(action:any){
if( window.innerWidth < 701){
this.popoverController.dismiss(action);
}
else{
this.modalController.dismiss(action)
}
}
//Top menu options
//Close
async setRoomOwner() {
let classs;
if (window.innerWidth < 701) {
classs = 'modal modal-desktop'
} else {
classs = 'centered-rounded-modal'
}
const modal = await this.modalController.create({
component: SetRoomOwnerPage,
cssClass: classs,
backdropDismiss: true,
componentProps: {
roomId: this.roomId,
isAdmin: this.isAdmin
}
});
await modal.present();
modal.onDidDismiss().then((res)=>{
if(res.data == 'success'){
this.leaveGroup();
//this.ChatSystemService.hidingRoom(this.roomId);
}
});
}
setAdmin() {
this.setRoomOwner();
}
async leaveGroup() {
//this.setRoomOwner();
this.showLoader = true
const result = await this.ChatServiceService.leaveRoom({
id: this.roomId,
members: [SessionStore.user.UserId]
})
if(result.isOk()) {
this.close('leave');
// this.openGroupMessage.emit(this.roomId);
} else if (isHttpResponse(result.error)) {
if(result.error.status == 404) {
this.close('leave');
}
// this.httpErrorHandle.httpStatusHandle(result.error)
} else if (result.error instanceof ZodError) {
this.toastService._badRequest("Pedimos desculpa mas não foi possível executar a acção. Por favor, contacte o apoio técnico.")
console.log(result.error.errors)
} else {
this.toastService._badRequest("Pedimos desculpa mas não foi possível executar a acção. Por favor, contacte o apoio técnico.")
console.log(result.error)
}
this.showLoader = false
}
//Delete
async deleteGroup() {
this.showLoader = true
const result = await this.ChatServiceService.deleteRoomById(this.roomId)
if(result.isOk()) {
this.close('delete');
// this.openGroupMessage.emit(this.roomId);
} else if (isHttpResponse(result.error)) {
if(result.error.status == 404) {
this.close('close');
}
} else if (result.error instanceof ZodError) {
this.toastService._badRequest("Pedimos desculpa mas não foi possível executar a acção. Por favor, contacte o apoio técnico.")
console.log(result.error.errors)
} else {
this.toastService._badRequest("Pedimos desculpa mas não foi possível executar a acção. Por favor, contacte o apoio técnico.")
console.log(result.error)
}
this.showLoader = false
}
async openChangeGroupName(){
this.close('edit');
}
async addUser() {
this.close('addUser');
}
async details() {
const modal = await this.modalController.create({
component: RoomInfoPage,
cssClass: 'modal-aside',
backdropDismiss: true,
componentProps: {
roomId: this.roomId
}
});
await modal.present();
modal.onDidDismiss().then((res)=>{
if(res.data == 'success') {
this.leaveGroup();
//this.ChatSystemService.hidingRoom(this.roomId);
}
});
}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { EditGroupPage } from './edit-group.page';
const routes: Routes = [
{
path: '',
component: EditGroupPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class EditGroupPageRoutingModule {}
@@ -0,0 +1,25 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { EditGroupPageRoutingModule } from './edit-group-routing.module';
import { EditGroupPage } from './edit-group.page';
import { SharedModule } from 'src/app/shared/shared.module';
import { BtnSeguintePageModule } from 'src/app/shared/btn-seguinte/btn-seguinte.module';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
EditGroupPageRoutingModule,
BtnSeguintePageModule,
],
declarations: [EditGroupPage]
})
export class EditGroupPageModule {}
@@ -0,0 +1,44 @@
<ion-header class="ion-no-border">
<ion-toolbar class="header-toolbar">
<div class="main-header">
<div class="title-content width-100">
<div class="left">
<button class="btn-no-color" (click)="close()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="end" src='assets/images/icons-arrow-arrow-left.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="end" src='assets/images/theme/gov/icons-calendar-arrow-left.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'doneIt' " slot="end" src='assets/images/theme/{{ThemeService.currentTheme}}/icons-calendar-arrow-left.svg'></ion-icon>
</button>
</div>
<div class="middle">
<ion-label class="title">Alterar assunto</ion-label>
</div>
<app-btn-seguinte *ngIf="groupName" (click)="changeGroupName()"></app-btn-seguinte>
</div>
</div>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="main-content">
<div class="item-container">
<ion-input [(ngModel)]="groupName" placeholder="Título"></ion-input>
</div>
<div *ngIf="false" class="item-container-no-border">
<ion-checkbox (ionChange)="_ionChange($event)" color="primary"></ion-checkbox>
<ion-label>Grupo Ultra-secreto</ion-label>
</div>
<div *ngIf="showDuration" class="container-div">
<div class="ion-item-class-2">
<div class="ion-icon-class">
<ion-icon slot="start" src="assets/images/icons-duration.svg"></ion-icon>
</div>
<div class="ion-input-class">
<ion-input (click)="showPicker()" [(ngModel)]="displayDuration" placeholder="Duração"></ion-input>
</div>
</div>
</div>
</div>
</ion-content>
@@ -0,0 +1,152 @@
@import '~src/function.scss';
ion-content{
--background:transparent;
}
.header-toolbar{
--background:transparent;
--opacity: 1;
}
.div-top-header{
width: 400px;
margin: 0 auto;
background-color: #0782c9;
overflow: auto;
padding-top: 15px;
border: 0!important;
.div-search{
font-size: rem(45);
float: left;
margin: 0 0 0 10px
}
.div-logo{
background: transparent;
width: 140px;
margin: 5px 0 0px 71px;
float: left;
}
.div-logo img{
width: 100%;
}
.div-profile{
font-size: rem(45);
float: right;
margin-right: 10px;
}
}
.main-header{
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-color: #fff;
overflow:hidden;
padding: 30px 20px 0px 20px;
color:#000;
transform: translate3d(0, 1px, 0);
.title-content{
margin: 0px auto;
overflow: auto;
padding: 0 !important;
background: #fff;
.left{
width: 37px;
float: left;
font-size: rem(35);
overflow: auto;
}
.middle{
padding: 0!important;
float: left;
width: 221px;
margin: 2.5px 0 0 5px;
}
.right{
padding: 0!important;
float: right;
font-size: rem(15);
color: #0782c9;
margin: 8px 0 0 5px;
}
}
.title{
font-size: rem(25);
}
.div-icon{
width: rem(40);
float: right;
font-size: rem(35);
overflow: auto;
padding: 1px;
}
.div-icon ion-icon{
float: right;
padding-left: 20px;
}
}
.main-content{
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
margin: 0 auto;
background-color: #fff;
overflow:auto;
padding: 15px 20px 0 20px;
.item-container{
width: 360px;
margin: 15px auto;
border: 1px solid #ebebeb;
border-radius: 5px;
padding-left: 10px;
}
.item-container-no-border{
display: flex;
width: 360px;
margin: 25px auto;
border-radius: 5px;
align-items: center;
}
.item-container-no-border ion-label{
padding-left: 10px;
font-size: rem(12);
color: #000;
}
}
.container-div{
margin-bottom: 15px;
overflow: auto;
.ion-item-class-2{
width: 360px;
margin: 0px auto;
.ion-icon-class{
width: rem(45);
height: rem(45);
float: left;
padding: 10px;
font-size: rem(25);
}
}
.ion-input-class{
width: 315px;
height: rem(45);
border: 1px solid #ebebeb;
border-radius: 5px;
padding-left: 5px;
padding-right: 10px;
float: left;
}
}
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { EditGroupPage } from './edit-group.page';
describe('EditGroupPage', () => {
let component: EditGroupPage;
let fixture: ComponentFixture<EditGroupPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ EditGroupPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(EditGroupPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,171 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { ModalController, NavParams, PickerController } from '@ionic/angular';
import { ThemeService } from 'src/app/services/theme.service'
@Component({
selector: 'app-edit-group',
templateUrl: './edit-group.page.html',
styleUrls: ['./edit-group.page.scss'],
})
export class EditGroupPage implements OnInit {
showLoader: boolean;
displayDuration: any;
showDuration: boolean;
selectedDuration = ['','',''];
groupName:string;
room:any;
roomId:string;
constructor(
private modalController: ModalController,
private pickerController: PickerController,
private navParams: NavParams,
public ThemeService: ThemeService
) {
this.roomId = this.navParams.get('roomId');
}
ngOnInit() {
// this.chatService.refreshtoken();
this.getRoomInfo();
}
getRoomInfo(){
}
close(){
this.modalController.dismiss();
}
changeGroupName(){
if(this.groupName.trim().length > 1){
let name = this.groupName.split(' ').join('-');
let body = {
"roomId": this.room._id,
"name": name,
}
}
else{
}
}
_ionChange(event){
this.showDuration = event.detail.checked;
}
async showPicker(){
const picker = await this.pickerController.create({
cssClass: '',
buttons: [
{
text: 'Cancelar', role: 'cancel', cssClass: 'btn-cancel'
},
{
text: 'Ok',
cssClass: 'btn-cancel',
handler:(value:any)=>{
this.selectedDuration = [
value.days.value,
value.hours.value,
value.minutes.value,
]
if(value.days.value != null && value.hours.value != null && value.minutes.value != null){
if(value.days.value > 0){
if(value.days.value == 1){
if(value.hours.value == 1){
this.displayDuration = value.days.value + " day " +
value.hours.value + " hora " +
value.minutes.value + " minutos";
}
else{
this.displayDuration = value.days.value + " days " +
value.hours.value + " horas " +
value.minutes.value + " minutos";
}
}
else{
if(value.hours.value == 1){
this.displayDuration = value.days.value + " days " +
value.hours.value + " hora " +
value.minutes.value + " minutos";
}
else{
this.displayDuration = value.days.value + " days " +
value.hours.value + " horas " +
value.minutes.value + " minutos";
}
}
}
else{
if(value.hours.value == 1){
this.displayDuration = value.hours.value + " hora " +
value.minutes.value + " minutos";
}
else{
this.displayDuration = value.hours.value + " horas " +
value.minutes.value + " minutos";
}
}
}
},
},
],
columns: [
{
name: 'days',
prefix: 'Dias',
options: [
{ text: '0', value: 0 },
{ text: '1', value: 1 },
{ text: '2', value: 2 },
{ text: '3', value: 3 },
{ text: '4', value: 4 },
]
},
{
name: 'hours',
prefix: 'Horas',
options: [
{ text: '0', value: 0 },
{ text: '1', value: 1 },
{ text: '2', value: 2 },
{ text: '3', value: 3 },
{ text: '4', value: 4 },
{ text: '5', value: 5 },
{ text: '6', value: 6 },
{ text: '7', value: 7 },
{ text: '8', value: 8 },
]
},
{
name: 'minutes',
prefix: 'Minutos',
selectedIndex: 0,
options: [
{ text: '5', value: 5 },
{ text: '10', value: 10 },
{ text: '15', value: 15 },
{ text: '20', value: 20 },
{ text: '25', value: 25 },
{ text: '30', value: 30 },
{ text: '35', value: 35 },
{ text: '45', value: 45 },
{ text: '50', value: 50 },
{ text: '55', value: 55 },
]
}
]
});
await picker.present();
picker.onDidDismiss().then(async data =>{
let day = await picker.getColumn('days');
let hour = await picker.getColumn('hours');
let minutes = await picker.getColumn('minutes');
});
}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { EditMessagePage } from './edit-message.page';
const routes: Routes = [
{
path: '',
component: EditMessagePage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class EditMessagePageRoutingModule {}
@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { EditMessagePageRoutingModule } from './edit-message-routing.module';
import { EditMessagePage } from './edit-message.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
EditMessagePageRoutingModule
],
declarations: [EditMessagePage]
})
export class EditMessagePageModule {}
@@ -0,0 +1,49 @@
<ion-header class="ion-no-border">
<ion-toolbar class="header-toolbar">
<div class="main-header">
<div class="title-content width-100">
<div class="back-icon">
<button class="btn-no-color cursor-pointer" (click)="dismiss()" >
<ion-icon *ngIf="ThemeService.currentTheme == 'doneIt' " slot="end" src='assets/images/theme/{{ThemeService.currentTheme}}/icons-arrow-arrow-left.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="end" src='assets/images/icons-arrow-arrow-left.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="end" src='assets/images/theme/gov/icons-calendar-arrow-left.svg'></ion-icon>
</button>
</div>
<div class="div-title">
<ion-label class="title">Editar Mensagem</ion-label>
</div>
</div>
</div>
</ion-toolbar>
</ion-header>
<div class="main-content">
<div class="old-message-container d-flex justify-center">
<div class="old-message" style="white-space: pre-line;">{{ oldMessage }}</div>
</div>
<div class="d-flex align-center mt-40-em mb-40-em mr-20">
<div class="type-message flex-1 ml-30 mr-20">
<ion-textarea
#messageInput
placeholder="Escrever uma mensagem"
class="message-input "
rows="1"
autoGrow="true"
[(ngModel)]="message"
(keyup.enter)="save()"
clearOnEdit="false"
></ion-textarea>
</div>
<button class="btn-no-color" (click)="save()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button>
</div>
</div>
@@ -0,0 +1,89 @@
@import '~src/function.scss';
.header-toolbar{
--background:transparent;
--opacity: 1;
.main-header{
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-color: #fff;
overflow:hidden;
padding: 30px 20px 0px 20px;
color:#000;
transform: translate3d(0, 1px, 0);
.div-icon{
width: rem(40);
float: right;
font-size: rem(35);
overflow: auto;
padding: 1px;
}
.div-icon ion-icon{
float: right;
padding-left: 20px;
}
.title-content{
margin: 0px auto;
overflow: auto;
padding: 0 !important;
}
.back-icon{
width: 37px;
float: left;
font-size: rem(35);
overflow: auto;
}
.div-title{
width: calc(100% - 45px);
padding: 0!important;
float: left;
margin: 2.5px 0 0 5px;
}
.title{
font-size: rem(25);
}
}
}
ion-content{
--background:transparent;
}
.main-content{
width: 100%;
height: 100%;
font-family: Roboto;
margin: 0 auto;
background-color: #fff;
overflow:auto;
padding: 0 0 0 0;
}
.type-message {
display: flex;
border: 1px solid #ebebeb;
border-radius: 25px;
align-items: center;
overflow: auto;
}
.old-message-container {
padding: 40px;
}
.old-message {
font-size: rem(13);
font-family: Roboto;
overflow: auto;
background: var(--chat-incoming-msg-color);
border-radius: 10px;
display: inline;
padding: 10px 20px;
}
@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { EditMessagePage } from './edit-message.page';
describe('EditMessagePage', () => {
let component: EditMessagePage;
let fixture: ComponentFixture<EditMessagePage>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ EditMessagePage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(EditMessagePage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,41 @@
import { Component, OnInit, Input, ViewChild, ElementRef } from '@angular/core';
import { ModalController, PopoverController } from '@ionic/angular';
import { ThemeService } from 'src/app/services/theme.service'
@Component({
selector: 'app-edit-message',
templateUrl: './edit-message.page.html',
styleUrls: ['./edit-message.page.scss'],
})
export class EditMessagePage implements OnInit {
@ViewChild('messageInput', { static: false }) messageInput!: ElementRef<HTMLIonTextareaElement>;
@Input() message: string;
@Input() roomId: any;
oldMessage: string
constructor(
public popoverController: PopoverController,
public ThemeService: ThemeService,
) {}
ngOnInit() {
this.oldMessage = this.message
}
ngAfterViewInit() {
// Focus the textarea once the view has been initialized
// this.messageInput.nativeElement.focus();
}
dismiss() {
this.popoverController.dismiss();
}
save() {
this.popoverController.dismiss({
'message': this.message
});
}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GroupDurationPage } from './group-duration.page';
const routes: Routes = [
{
path: '',
component: GroupDurationPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class GroupDurationPageRoutingModule {}
@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { GroupDurationPageRoutingModule } from './group-duration-routing.module';
import { GroupDurationPage } from './group-duration.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
GroupDurationPageRoutingModule
],
declarations: [GroupDurationPage]
})
export class GroupDurationPageModule {}
@@ -0,0 +1,19 @@
<ion-content>
<div class="p-header">
<h3>Duração</h3>
</div>
<div class="picker">
</div>
<div class="p-buttons">
<ion-row>
<ion-col>
<button (click)="close()" full class="btn-cancel" shape="round" >Cancelar</button>
</ion-col>
<ion-col>
<button class="btn-ok" shape="round" >Ok</button>
</ion-col>
</ion-row>
</div>
</ion-content>
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { GroupDurationPage } from './group-duration.page';
describe('GroupDurationPage', () => {
let component: GroupDurationPage;
let fixture: ComponentFixture<GroupDurationPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ GroupDurationPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(GroupDurationPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,21 @@
import { Component, OnInit } from '@angular/core';
import { PopoverController } from '@ionic/angular';
@Component({
selector: 'app-group-duration',
templateUrl: './group-duration.page.html',
styleUrls: ['./group-duration.page.scss'],
})
export class GroupDurationPage implements OnInit {
constructor(
public popoverController: PopoverController,
) { }
ngOnInit() {
}
close(){
this.popoverController.dismiss();
}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GroupContactsPage } from './group-contacts.page';
const routes: Routes = [
{
path: '',
component: GroupContactsPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class GroupContactsPageRoutingModule {}
@@ -0,0 +1,27 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { GroupContactsPageRoutingModule } from './group-contacts-routing.module';
import { GroupContactsPage } from './group-contacts.page';
import { SharedModule } from 'src/app/shared/shared.module';
import { PipesModule } from 'src/app/pipes/pipes.module';
import { BtnSeguintePageModule } from 'src/app/shared/btn-seguinte/btn-seguinte.module';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
PipesModule,
GroupContactsPageRoutingModule,
BtnSeguintePageModule,
],
declarations: [GroupContactsPage]
})
export class GroupContactsPageModule {}
@@ -0,0 +1,65 @@
<ion-header class="ion-no-border">
<ion-toolbar class="header-toolbar">
<div class="main-header">
<div class="title-content width-100">
<div class="back-icon">
<button class="btn-no-color cursor-pointer" (click)="close()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="end" src='assets/images/icons-arrow-arrow-left.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'doneIt' " src="assets/images/theme/doneIt/icons-calendar-arrow-left.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="end" src='assets/images/theme/gov/icons-calendar-arrow-left.svg'></ion-icon>
</button>
</div>
<div class="div-title">
<ion-label class="title">Contactos</ion-label>
</div>
<app-btn-seguinte (click)="updateGroup()"></app-btn-seguinte>
</div>
</div>
</ion-toolbar>
<ion-toolbar class="toolbar-search">
<div class="search">
<ion-searchbar search-icon="undefined" debounce="500" (ionChange)="onChange($event)" placeholder="Pesquisar por contacto" ></ion-searchbar>
</div>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-refresher name="refresher" slot="fixed" (ionRefresh)="doRefresh($event)">
<ion-progress-bar type="indeterminate" *ngIf="showLoader"></ion-progress-bar>
<ion-refresher-content>
</ion-refresher-content>
</ion-refresher>
<div class="main-content">
<div *ngIf="members">
<ion-label class="members-label">Contactos selecção:</ion-label>
<div class="members-list" *ngFor="let user of members">
<ion-item-sliding [class.inactive]="sessionStore.user.UserName == user.username">
<ion-item lines="none" class="members-checkbox ion-no-border ion-no-padding">
<ion-checkbox checked disabled color="primary"></ion-checkbox>
<p>{{user.name}}</p>
<ion-icon class="{{user.status}}" name="ellipse"></ion-icon>
</ion-item>
<ion-item-options (click)="deleteMember(user)" class="members-options" side="end">
<ion-item-option color="danger">Apagar</ion-item-option>
</ion-item-options>
</ion-item-sliding>
</div>
</div>
<div *ngFor="let userContainer of userContainer | keyvalue;" >
<div class="item-divider">
<ion-label>{{ userContainer.key }}</ion-label>
</div>
<div *ngFor="let user of userContainer.value" class="d-flex px-20 align-center">
<ion-checkbox [(ngModel)]="user.isChecked" color="primary" (click)="selectedContact(user)"></ion-checkbox>
<ion-label class="flex-grow-1 px-10">{{user.name}}</ion-label>
<div class="icon"><ion-icon class="{{user.status}}" name="ellipse"></ion-icon></div>
</div>
</div>
</div>
</ion-content>
@@ -0,0 +1,173 @@
@import '~src/function.scss';
.header-toolbar{
--background:transparent;
--opacity: 1;
.main-header{
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-color: #fff;
overflow:hidden;
padding: 30px 20px 0px 20px;
color:#000;
transform: translate3d(0, 1px, 0);
.div-icon{
width: rem(40);
float: right;
font-size: rem(35);
overflow: auto;
padding: 1px;
}
.div-icon ion-icon{
float: right;
padding-left: 20px;
}
.title-content{
margin: 0px auto;
overflow: auto;
padding: 0 !important;
}
.back-icon{
width: 37px;
float: left;
font-size: rem(35);
overflow: auto;
}
.div-title{
width: 221px;
padding: 0!important;
float: left;
margin: 2.5px 0 0 5px;
}
.title{
font-size: rem(25);
}
}
}
.toolbar-search{
--padding-top:0 !important;
--padding-bottom:0 !important;
--padding-start:0 !important;
--padding-end:0 !important;
.search{
border: 1px solid #ebebeb;
margin: 5px 20px 5px 20px;
border-radius: 5px;
}
.search ion-searchbar{
/* border: 1px solid green; */
width: 100%;
margin: 0 !important;
padding: 0 !important;
--border-radius: 5px;
--box-shadow: none;
overflow: auto;
--icon-color: var(--font-awesome);
}
}
ion-content{
--background:transparent;
}
.main-content{
width: 100%;
height: 100%;
font-family: Roboto;
margin: 0 auto;
background-color: #fff;
overflow:auto;
padding: 0 0 0 0;
.members-label{
margin: 10px 20px 10px 20px !important;
/* font-size: rem(15); */
font-weight: bold;
}
.members-checkbox{
display: flex;
margin: 0px 20px 0px 20px !important;
overflow: auto;
align-items: center;
border-bottom: 1px solid #ebebeb;
}
.members-options{
margin: 0px 20px 0px 19px !important;
overflow: auto;
}
.item-divider{
background: #ebebeb;
font-size: rem(15);
margin: 10px 0 10px 0;
padding:5px 0 5px 20px;
}
.item-checkbox{
display: flex;
margin: 10px 20px 10px 20px !important;
overflow: auto;
align-items: center;
}
.members-checkbox ion-checkbox{
--border-color: var(--title-text-color);
--background-checked:var(--title-text-color);
float: left;
}
.item-checkbox ion-checkbox{
--border-color: var(--title-text-color);
--background-checked:var(--title-text-color);
float: left;
}
.item-checkbox p, .members-checkbox p{
display: block;
margin: 0 !important;
padding-left: 10px;
font-size: rem(15);
color: var(--title-text-color);
float: left;
}
.item-checkbox ion-icon, .members-checkbox ion-icon{
font-size: rem(10);
float: left;
color:#99e47b;
margin-left: 10px;
}
.online{
color:#99e47b !important;
}
.offline{
color:#cbced1 !important;
}
.away{
color:#ffd21f !important;
}
.invisible{
color:#cbced1 !important;
}
.busy{
color:#f5455c !important;
}
}
.inactive {
opacity: 0.7;
ion-item-options {
display: none !important;
}
}
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { GroupContactsPage } from './group-contacts.page';
describe('GroupContactsPage', () => {
let component: GroupContactsPage;
let fixture: ComponentFixture<GroupContactsPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ GroupContactsPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(GroupContactsPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,279 @@
import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { ModalController, NavParams } from '@ionic/angular';
import * as _ from 'lodash';
import { AuthService } from 'src/app/services/auth.service';
import { GroupMessagesPage } from '../group-messages.page';
import { ThemeService } from 'src/app/services/theme.service'
import { SessionStore } from 'src/app/store/session.service';
// import { ChatSystemService } from 'src/app/services/chat/chat-system.service';
@Component({
selector: 'app-group-contacts',
templateUrl: './group-contacts.page.html',
styleUrls: ['./group-contacts.page.scss'],
})
export class GroupContactsPage implements OnInit {
showLoader: boolean;
users = [];
contact: string[] = [" Ana M.", "Andre F.", "Bruno G.", "Catarina T", "Tiago"];
headers: HttpHeaders;
options:any;
listContacts: any[];
contacts: any;
textSearch:string;
room:any;
members:any;
dm:any;
isGroupCreated:boolean;
groupName:string;
selectedUserList:any;
sessionStore = SessionStore
objectUserSingleStone = []
userContainer = {}
constructor(
private modalController: ModalController,
public ThemeService: ThemeService,
// public ChatSystemService: ChatSystemService,
)
{
// this.textSearch="";
// this.dm=null;
// this.room=null;
// this.isGroupCreated = this.navParams.get('isCreated');
// this.groupName = this.navParams.get('name');
// this.room = this.navParams.get('room');
// this.members = this.navParams.get('members');
}
ngOnInit() {
// this.chatService.refreshtoken();
this.loadUsers();
// this.getMembers();
}
loadUsers(){
// this.options = {
// headers: this.headers,
// };
// this.chatService.getAllUsers().subscribe((res:any)=>{
// if(this.members) {
// this.contacts = res.users.filter(f => !this.members.some(item => item._id === f._id));
// }
// else{
// this.contacts = res.users.filter(data => data.username != this.sessionStore.user.UserName);
// }
// this.users = this.contacts.sort((a,b) => {
// if(a.name < b.name){
// return -1;
// }
// if(a.name > b.name){
// return 1;
// }
// return 0;
// });
// for( const user of this.users) {
// const foundUser = this.objectUserSingleStone.find( e => e.name == user.name)
// if(!foundUser) {
// this.objectUserSingleStone.push(user)
// } else {
// 'not found'
// }
// }
// const userContainer = {}
// for(const user of this.objectUserSingleStone) {
// const firstLetter = user.name.charAt(0)
// if(!userContainer[firstLetter]) {
// userContainer[firstLetter] = [user]
// } else {
// userContainer[firstLetter].push(user)
// }
// }
// this.userContainer = userContainer
// this.showLoader = false;
// });
}
getMembers(){
}
separateLetter(record, recordIndex, records){
if(recordIndex == 0){
return record.name[0];
}
let first_prev = records[recordIndex - 1].name[0];
let first_current = record.name[0];
if(first_prev != first_current){
return first_current;
}
return null;
}
deleteMember(data:any){
let body = {
"roomId": this.room._id,
"userId": data._id,
}
if(this.room.t == "p"){
}
else if(this.room.t == "c"){
}
}
doRefresh(ev){
this.loadUsers();
//this.getMembers();
ev.target.complete();
}
async close(){
this.modalController.dismiss();
}
onChange(event) {
this.textSearch = event.detail.value;
const users = this.contacts.filter( e => e.name.toLowerCase().includes(this.textSearch.toLowerCase())).sort((a,b) => {
if(a.name < b.name) {
return -1;
}
if(a.name > b.name) {
return 1;
}
return 0;
});
const selectedUsers = this.users.filter( e => e?.isChecked == true)
users.forEach( (user, index) => {
if(user[index]) {
console.log({user, index})
const isCheck = selectedUsers.find( e => e._id == user._id)?.isChecked
if(isCheck) {
user[index].isChecked = isCheck
}
// if(user[index].isChecked) {
// console.log('user[index].isChecked', user[index].isChecked)
// }
}
})
let a = this.objectUserSingleStone.filter( e => e.name.toLowerCase().includes(this.textSearch.toLowerCase()))
let b = {}
for(const user of a) {
const firstLetter = user.name.charAt(0)
if(!b[firstLetter]) {
b[firstLetter] = [user]
} else {
b[firstLetter].push(user)
}
}
this.userContainer = b
}
clicked(){
}
selectedContact(user:any) {
/* this.groupName = this.room.name; */
if(user.isChecked != true ) {
user.isChecked = false
} else {
user.isChecked = true
}
const userIndex = this.objectUserSingleStone.findIndex((e) => e._id == user._id)
this.objectUserSingleStone[userIndex].isChecked = user.isChecked
}
addContacts(room:any){
this.selectedUserList = this.users.filter(function(contact) {
return contact.isChecked == true;
});
this.selectedUserList.forEach(user=>{
let body ={
"roomId":room._id,
"userId":user._id,
}
});
}
loading = false
updateGroup(){
if(this.loading) {
return
}
this.loading = true
console.log('this.room', this.room)
}
async openGroupMessages(roomId:any){
const modal = await this.modalController.create({
component: GroupMessagesPage,
componentProps: {
roomId: roomId,
},
cssClass: 'group-messages',
backdropDismiss: false
});
modal.onDidDismiss().then(() => {
this.close();
});
await modal.present();
}
}
@@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { GroupMessagesPage } from './group-messages.page';
const routes: Routes = [
{
path: '',
component: GroupMessagesPage
},
{
path: 'group-contacts',
loadChildren: () => import('./group-contacts/group-contacts.module').then( m => m.GroupContactsPageModule)
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
@@ -0,0 +1,36 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { IonicModule } from '@ionic/angular';
import { GroupMessagesPageRoutingModule } from './group-messages-routing.module';
import { GroupMessagesPage } from './group-messages.page';
import { BtnModalDismissPageModule } from 'src/app/shared/btn-modal-dismiss/btn-modal-dismiss.module';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { LettersAvatarModule } from "ngx-letters-avatar";
import { PipesModule } from 'src/app/pipes/pipes.module';
import { ChatPopoverPageModule } from '../chat-popover/chat-popover.module';
@NgModule({
imports: [
CommonModule,
FormsModule,
FontAwesomeModule,
IonicModule,
GroupMessagesPageRoutingModule,
ChatPopoverPageModule,
BtnModalDismissPageModule,
LettersAvatarModule,
PipesModule,
/* ImageCropperModule,
AngularCropperjsModule */
],
declarations: [GroupMessagesPage]
})
export class GroupMessagesPageModule {}
@@ -0,0 +1,441 @@
@import '~src/function.scss';
.header-toolbar {
--background: transparent;
--opacity: 1;
.main-header {
width: 100%;
/* 400px */
height: 100%;
font-family: Roboto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-color: #fff;
overflow: hidden;
padding: 30px 20px 0px 20px;
color: #000;
transform: translate3d(0, 1px, 0);
.header-top {
overflow: auto;
padding: 0 !important;
background: #fff;
.left {
width: fit-content;
float: left;
//font-size: rem(35);
overflow: hidden;
}
.middle-container {
display: flex;
overflow: auto;
height: auto;
width: calc(100% - 47px);
float: left;
/* white-space: nowrap;
overflow: hidden !important;
text-overflow: ellipsis !important; */
.middle {
width: 100%;
padding: 0 !important;
margin: 0 0 0 10px;
font-size: rem(25);
}
}
.middle-container-options {
padding: 0 !important;
float: left;
width: calc(100% - 67px);
text-align: right;
.middle-container-options-icons {
color: #0782c9;
font-size: rem(23);
}
}
.right {
padding: 0 !important;
float: right;
font-size: rem(25);
color: #0782c9;
}
.header-top-btn {
background: transparent;
font-size: rem(25) !important;
font-weight: 100 !important;
/* color: #0782c9; */
color: #42b9fe;
padding: 0 5px 0 5px;
}
}
.header-bottom {
padding-left: 10px;
overflow: auto;
margin: 0 auto;
.header-bottom-icon {
width: rem(30);
font-size: rem(25);
float: left;
padding: 2px;
}
.header-bottom-contacts {
width: calc(100% - 40px);
font-size: rem(15);
color: #797979;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
float: left;
padding: 5px;
margin: 1px;
.contacts-list {
white-space: nowrap;
overflow: hidden !important;
text-overflow: ellipsis !important;
}
}
}
.div-icon {
width: rem(40);
float: right;
font-size: rem(35);
overflow: auto;
padding: 1px;
}
.div-icon ion-icon {
float: right;
padding-left: 20px;
}
}
}
ion-content {
.welcome-text {
/* width: 322px; */
width: em(422px);
background: #ebebeb;
text-align: center;
font-size: rem(13);
color: #797979;
padding: 10px;
margin: 0 auto !important;
line-height: 1.2rem;
// margin: 20px 39px 25px;
border-radius: 8px;
}
.info-text {
display: flex;
width: fit-content;
height: auto;
background: var(--chat-alert-msg-color);
text-align: center;
font-size: rem(13);
color: #262420;
padding: 10px;
margin: 10px auto;
line-height: 1.2rem;
border-radius: 8px;
}
.info-text-leave {
display: flex;
align-items: center;
justify-content: center;
width: fit-content;
padding: 10px;
background: #e0e9ee;
border-radius: 8px;
margin: 10px auto;
color: #797979 !important;
font-size: rem(13) !important;
/* margin: 15px 0px 15px 0px; */
.info-text-leave ion-label {
font-size: rem(13) !important;
line-height: 1.2rem;
}
}
.messages {
font-size: rem(13);
font-family: Roboto;
overflow: auto;
//set scroll do bottom
position: absolute;
top: 0;
left: 0;
overflow-x: hidden;
overflow-y: auto;
width: 100%;
height: 100%;
word-wrap: break-word;
-webkit-overflow-scrolling: touch;
.messages-list-item-wrapper {
overflow: hidden;
}
.messages-list-item-wrapper-active {
background: #e6f6ff75 !important;
}
.message-container {
//border: 1px solid red;
}
.incoming-true,
.incoming-false {
width: 305px;
padding: 15px 20px;
border-radius: 10px;
}
.incoming-true {
margin: 10px 35px 10px 20px;
background: #ebebeb;
float: left;
}
}
.incoming-false {
margin: 10px 20px 10px 35px;
background: var(--chat-incoming-msg-color);
float: right;
}
.title {
color: var(--title-text-color);
font-weight: bold;
margin-bottom: 5px;
.time {
color: #797979;
text-align: right;
float: right;
}
}
.online {
color: #99e47b !important;
}
.offline {
color: #cbced1 !important;
}
.away {
color: #ffd21f !important;
}
.invisible {
color: #cbced1 !important;
}
.busy {
color: #f5455c !important;
}
}
.info-meeting {
/* width: 322px; */
width: em(422);
background: var(--chat-alert-msg-color);
text-align: center;
font-size: rem(13);
color: #262420;
padding: 10px;
margin: 10px auto;
line-height: 1.2rem;
/* margin: 15px 0px 15px 0px; */
border-radius: 8px;
.info-meeting-small {
font-size: rem(10);
font-style: italic;
}
.info-meeting-medium {
font-size: rem(12);
}
.info-meeting-normal {
color: #0782c9;
font-weight: 700;
text-decoration: underline;
}
.info-meeting-normal:hover {
text-decoration: underline;
color: #0782c9;
}
}
ion-footer {
padding-top: 7.5px;
padding-bottom: 20px;
.container {
justify-content: center;
justify-content: space-evenly;
align-items: center;
.message-box {
margin: 0 5px 0 5px;
}
}
.chat-icon-options {
display: block !important;
font-size: rem(35);
float: right !important;
margin-top: 5px;
}
.chat-icon-send {
font-size: rem(40);
margin: 0 auto;
margin-top: 4px;
}
.type-message {
display: flex;
border: 1px solid #ebebeb;
border-radius: 25px;
padding-left: 15px;
align-items: center;
overflow: auto;
ion-textarea {
margin: 0 !important;
align-self: center;
}
}
}
.preview-slides {
margin-top: 20%;
background: #e6e6e6;
img {
padding-top: 20px;
padding-bottom: 20px;
}
}
.transparent-modal {
.modal-wrapper {
--background: rgba(44, 39, 45, 0.2);
}
}
.image-slide,
.image-card {
overflow: visible;
}
.image-card {
z-index: 9;
}
.backdrop {
height: 200%;
width: 100%;
background: black;
position: absolute;
z-index: 10;
}
.typing {
position: relative;
top: -25px;
height: 0px;
left: 0px;
margin-left: 22px;
display: flex;
font-size: rem(12);
align-items: center;
}
.typing ngx-letters-avatar {
padding-right: 5px;
}
.float-status {
position: relative !important;
float: right;
display: flex;
align-items: self-end;
}
.float-status-image {
position: relative !important;
float: right;
display: flex;
align-items: self-end;
top: -15px;
}
.float-status-webtrix {
position: relative !important;
top: 0px !important;
float: right;
display: flex;
align-items: self-end;
}
.float-status-all {
font-size: rem(13) !important;
}
.try {
color: red;
background: #f3414159;
padding: 6px;
border-radius: 10px;
cursor: pointer;
}
.font-40-rem {
font-size: 2.5rem !important;
}
.dateLabel {
background: #ebebeb !important;
float: unset !important;
margin: 0px auto !important;
width: 111px;
text-align: center;
margin-top: 10px !important;
padding: 15px 20px;
border-radius: 10px;
}
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { GroupMessagesPage } from './group-messages.page';
describe('GroupMessagesPage', () => {
let component: GroupMessagesPage;
let fixture: ComponentFixture<GroupMessagesPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ GroupMessagesPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(GroupMessagesPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MessagesOptionsPage } from './messages-options.page';
const routes: Routes = [
{
path: '',
component: MessagesOptionsPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class MessagesOptionsPageRoutingModule {}
@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { MessagesOptionsPageRoutingModule } from './messages-options-routing.module';
import { MessagesOptionsPage } from './messages-options.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
MessagesOptionsPageRoutingModule
],
declarations: [MessagesOptionsPage]
})
export class MessagesOptionsPageModule {}
@@ -0,0 +1,10 @@
<ion-content class="container">
<div class="arrow-right">
<button class="btn-no-color" (click)="close()">
<ion-icon src='assets/images/theme/gov/icons-calendar-arrow-right.svg'></ion-icon>
</button>
</div>
<div class="buttons">
<button (click)="closeChatRoom()" full class="btn-delete" shape="round" >Apagar conversa</button>
</div>
</ion-content>
@@ -0,0 +1,60 @@
@import '~src/function.scss';
.container{
--padding-top:20px !important;
--padding-bottom:20px !important;
--padding-start:20px !important;
--padding-end:20px !important;
}
.arrow-right{
display: none;
margin-bottom: 20px;
.arrow-right-icon{
width: 37px;
float: right;
font-size: rem(35);
overflow: hidden;
}
}
.buttons{
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.solid {
display: block;
width: 90%;
border-top: 1px solid #bbb;
margin: 10px auto !important;
}
@media only screen and (min-width: 701px) {
.arrow-right{
display: flex;
justify-content: flex-end;
}
.btn-cancel{
//display: none;
width: 100% !important;
margin-bottom: 10px !important;
}
.btn-cancel:hover, .btn-delete:hover{
background-color: var(--button-hover);
color: #fff !important;
}
.btn-ok{
width: 100% !important;
}
.btn-delete{
width: 100% !important;
margin-bottom: 10px !important;
}
.solid{
display: block;
}
.mobile-only{
display: none !important;
}
}
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { MessagesOptionsPage } from './messages-options.page';
describe('MessagesOptionsPage', () => {
let component: MessagesOptionsPage;
let fixture: ComponentFixture<MessagesOptionsPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MessagesOptionsPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(MessagesOptionsPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,44 @@
import { Component, OnInit } from '@angular/core';
import { ModalController, NavParams, PopoverController } from '@ionic/angular';
import { ThemeService } from 'src/app/services/theme.service';
@Component({
selector: 'app-messages-options',
templateUrl: './messages-options.page.html',
styleUrls: ['./messages-options.page.scss'],
})
export class MessagesOptionsPage implements OnInit {
roomId:string;
constructor(
private popoverController: PopoverController,
private modalController: ModalController,
private navParams: NavParams,
public ThemeService: ThemeService,
)
{
this.roomId = this.navParams.get('roomId');
}
ngOnInit() {
// this.chatService.refreshtoken();
}
close(){
if( window.innerWidth <= 701){
this.modalController.dismiss();
this.popoverController.dismiss();
}
else{
this.modalController.dismiss();
this.popoverController.dismiss();
}
}
closeChatRoom(){
let body = { "roomId": this.roomId }
this.close();
}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ContactsPage } from './contacts.page';
const routes: Routes = [
{
path: '',
component: ContactsPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ContactsPageRoutingModule {}
@@ -0,0 +1,26 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { ContactsPageRoutingModule } from './contacts-routing.module';
import { ContactsPage } from './contacts.page';
import { SharedModule } from 'src/app/shared/shared.module';
import { PipesModule } from 'src/app/pipes/pipes.module';
import { FilterPipe } from 'src/app/pipes/filter.pipe';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
ContactsPageRoutingModule,
PipesModule,
],
declarations: [ContactsPage]
})
export class ContactsPageModule {}
@@ -0,0 +1,48 @@
<ion-header class="ion-no-border">
<ion-toolbar class="header-toolbar">
<div class="main-header">
<div class="title-content width-100">
<div class="back-icon ">
<button class="btn-no-color cursor-pointer" (click)="close()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="end" src='assets/images/icons-arrow-arrow-left.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'doneIt' " src="assets/images/theme/doneIt/icons-calendar-arrow-left.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="end" src='assets/images/theme/gov/icons-calendar-arrow-left.svg'></ion-icon>
</button>
</div>
<div class="div-title">
<!-- MOBILE -->
<ion-label class="title">Nova Conversa ..</ion-label>
</div>
</div>
</div>
</ion-toolbar>
<ion-toolbar class="toolbar-search">
<div class="search">
<ion-searchbar search-icon="undefined" debounce="500" (ionChange)="onChange($event)" placeholder="Pesquisar por contacto" ></ion-searchbar>
</div>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-refresher name="refresher" slot="fixed" (ionRefresh)="doRefresh($event)">
<ion-progress-bar type="indeterminate" *ngIf="loading"></ion-progress-bar>
<ion-refresher-content>
</ion-refresher-content>
</ion-refresher>
<div class="main-content">
<ion-progress-bar class="position-absolute" type="indeterminate" *ngIf="loading"></ion-progress-bar>
<div *ngFor="let userContainer of userContainer | keyvalue;" >
<div class="item-divider">
<ion-label>{{ userContainer.key }}</ion-label>
</div>
<div *ngFor="let user of userContainer.value; let i = index" class="d-flex px-20 align-center" (click)="select(user)">
<ion-label class="flex-grow-1 px-10 cursor-pointer">{{user.wxFullName}}</ion-label>
<div class="icon"><ion-icon name="ellipse"></ion-icon></div>
</div>
</div>
</div>
</ion-content>
@@ -0,0 +1,136 @@
@import '~src/function.scss';
.header-toolbar{
--background:transparent;
--opacity: 1;
.main-header{
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-color: #fff;
overflow:hidden;
padding: 30px 20px 0px 20px;
color:#000;
transform: translate3d(0, 1px, 0);
.div-icon{
width: rem(40);
float: right;
font-size: rem(35);
overflow: auto;
padding: 1px;
}
.div-icon ion-icon{
float: right;
padding-left: 20px;
}
.title-content{
margin: 0px auto;
overflow: auto;
padding: 0 !important;
}
.back-icon{
width: 37px;
float: left;
font-size: rem(35);
overflow: auto;
}
.div-title{
width: 221px;
padding: 0!important;
float: left;
margin: 2.5px 0 0 5px;
}
.title{
font-size: rem(25);
}
}
}
.toolbar-search{
--padding-top:0 !important;
--padding-bottom:0 !important;
--padding-start:0 !important;
--padding-end:0 !important;
.search{
border: 1px solid #ebebeb;
margin: 5px 20px 5px 20px;
border-radius: 5px;
height: auto;
padding: 0 !important;
}
.search ion-searchbar{
/* border: 1px solid green; */
width: 100%;
margin: 0 !important;
padding: 0 !important;
--border-radius: 5px;
--box-shadow: none;
overflow: hidden;
--icon-color: var( --font-awesome);
}
}
ion-content{
--background:transparent;
}
.main-content{
width: 100%;
height: 100%;
font-family: Roboto;
margin: 0 auto;
background-color: #fff;
overflow:auto;
padding: 0 0 0 0;
.item-divider{
background: #ebebeb;
font-size: rem(15);
margin: 10px 0 10px 0;
padding:5px 0 5px 20px;
}
.item-user{
display: flex;
margin: 10px 20px 10px 20px !important;
overflow: auto;
align-items: center;
}
.item-user p{
display: block;
margin: 0 !important;
width: 90%;
font-size: rem(15);
color: var(--title-text-color);
float: left;
}
.item-user .icon{
width: 10%;
font-size: rem(10);
display: block;
text-align: right;
overflow: auto;
}
.online{
color:#99e47b;
}
.offline{
color:#cbced1;
}
.away{
color:#ffd21f;
}
.invisible{
color:#cbced1;
}
.busy{
color:#f5455c;
}
}
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { ContactsPage } from './contacts.page';
describe('ContactsPage', () => {
let component: ContactsPage;
let fixture: ComponentFixture<ContactsPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ContactsPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(ContactsPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,184 @@
import { Component, OnInit } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { ThemeService } from 'src/app/services/theme.service'
import { SessionStore } from 'src/app/store/session.service';
import { ContactRepositoryService } from 'src/app/services/Repositorys/contacts/repository/contacts-repository.service';
import { UserContacts } from 'src/app/services/Repositorys/contacts/data-source/contacts-data-source.service';
import { HttpErrorHandle } from 'src/app/services/http-error-handle.service';
import { ToastService } from 'src/app/services/toast.service';
import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service'
import { MessageEntity } from 'src/app/core/chat/entity/message';
import { RoomType } from "src/app/core/chat/entity/group";
@Component({
selector: 'app-contacts',
templateUrl: './contacts.page.html',
styleUrls: ['./contacts.page.scss'],
})
export class ContactsPage implements OnInit {
loading: boolean;
loggedUser: any;
users = [];
contacts:any;
textSearch:string;
room:any;
dm:any;
sessionStore = SessionStore
userList: UserContacts[] = []
currentMembers:UserContacts[];
allChatUsers: UserContacts[] = [];
userContainer: {[key: string]: ( UserContacts & {isChecked: boolean})[] } = {}
selectedUsers: number[] =[]
SessionStore = SessionStore
constructor(
private modalController: ModalController,
public ThemeService: ThemeService,
private contactsRepositoryService: ContactRepositoryService,
private httpErrorHandle: HttpErrorHandle,
private toastService: ToastService,
private chatServiceService: ChatServiceService
)
{
this.loggedUser = SessionStore.user.ChatData['data'];
this.textSearch="";
this.dm=null;
this.room=null;
}
ngOnInit(): void {
this.loadUsers()
}
get hasMemberToUpload() {
return this.selectedUsers.length >= 1
}
async updateGroup() {
}
openGroupMessagesPage() {
// this.openGroupMessage.emit(this.roomId)
}
async loadUsers() {
this.loading = true
const getallChatUsers = await this.contactsRepositoryService.getUsers()
if(getallChatUsers.isOk()) {
this.allChatUsers = getallChatUsers.value.data.result.sort((a,b) => {
if(a.wxFullName < b.wxFullName) {
return -1;
}
if(a.wxFullName > b.wxFullName) {
return 1;
}
return 0;
});
for(const user of this.allChatUsers) {
const firstLetter = user.wxFullName.charAt(0)
if(!this.userContainer[firstLetter]) {
user['isChecked'] = false
this.userContainer[firstLetter] = [user as any]
} else {
const userIds = this.userContainer[firstLetter].map( e => e.wxUserId)
if(!userIds.includes(user.wxUserId)) {
user['isChecked'] = false
this.userContainer[firstLetter].push(user as any)
}
}
}
}
else if (getallChatUsers.isErr() ) {
console.log(getallChatUsers.error)
} else {
this.toastService._badRequest("Pedimos desculpa mas não foi possível executar a acção. Por favor, contacte o apoio técnico.")
}
this.loading = false;
}
doRefresh(ev) {
ev.target.complete();
}
FilterUserListedByTextSearch() {
return this.allChatUsers.filter( e => e.wxFullName.toLowerCase().includes(this.textSearch.toLowerCase())).sort((a,b) => {
if(a.wxFullName < b.wxFullName) {
return -1;
}
if(a.wxFullName > b.wxFullName) {
return 1;
}
return 0;
});
}
onChangeCheckBox(user: UserContacts & {isChecked: boolean}) {
if(user.isChecked) {
this.selectedUsers.push(user.wxUserId)
} else {
this.selectedUsers = this.selectedUsers.filter(e => e!= user.wxUserId)
}
}
onChange(event) {
this.textSearch = event.detail.value;
const filteredUserList: (UserContacts & {isChecked: boolean})[] = this.FilterUserListedByTextSearch() as any
const userContainer = {}
for(const user of filteredUserList) {
const firstLetter = user.wxFullName.charAt(0)
if(!userContainer[firstLetter]) {
user.isChecked = this.selectedUsers.includes(user.wxUserId)
userContainer[firstLetter] = [user]
} else {
user.isChecked = this.selectedUsers.includes(user.wxUserId)
userContainer[firstLetter].push(user)
}
}
this.userContainer = userContainer
}
close() {
this.modalController.dismiss({});
}
select(user: UserContacts) {
const message = new MessageEntity();
message.sender = {
userPhoto: '',
wxeMail: SessionStore.user.Email,
wxFullName: SessionStore.user.FullName,
wxUserId: SessionStore.user.UserId
}
message.receiverId = user.wxUserId
message.message = 'hello'
this.chatServiceService.sendMessage(message, RoomType.Group)
}
}
@@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MessagesPage } from './messages.page';
const routes: Routes = [
{
path: '',
component: MessagesPage
},
{
path: 'contacts',
loadChildren: () => import('./contacts/contacts.module').then( m => m.ContactsPageModule)
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
@@ -0,0 +1,30 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { MessagesPageRoutingModule } from './messages-routing.module';
import { MessagesPage } from './messages.page';
import { SharedModule } from 'src/app/shared/shared.module';
import { BtnModalDismissPage } from 'src/app/shared/btn-modal-dismiss/btn-modal-dismiss.page';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { MatMenuModule } from '@angular/material/menu';
import { LettersAvatarModule } from "ngx-letters-avatar";
import { PipesModule } from 'src/app/pipes/pipes.module';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
FontAwesomeModule,
MessagesPageRoutingModule,
MatMenuModule,
LettersAvatarModule,
PipesModule
],
declarations: [MessagesPage]
})
export class MessagesPageModule {}
@@ -0,0 +1,271 @@
<ion-header class="ion-no-border" >
<ion-toolbar class="header-toolbar">
<div class="main-header">
<div class="header-top">
<div class="left">
<button class="btn-no-color" (click)="close()">
<!-- <ion-icon slot="end" src='assets/images/icons-arrow-arrow-left.svg'></ion-icon> -->
<fa-icon icon="chevron-left" class="header-top-btn font-awesome-1"></fa-icon>
</button>
</div>
<div class="middle-container" *ngIf="!showMessageOptions">
<div class="middle" >
<ion-label *ngIf="roomData$ | async as roomData" class="title">{{ roomData.roomName }}</ion-label>
<span *ngIf="roomStatus$ | async as roomStatus"><ion-icon *ngIf="roomStatus"
class="online" name="ellipse"></ion-icon></span>
</div>
</div>
<!-- <div (click)="ChatSystemService.getDmRoom(roomId).deleteAll()" >delete all</div> -->
<div class="middle-container-options" *ngIf="showMessageOptions">
<fa-icon (click)="deleteMessage(selectedMsgId)" icon="trash" class="middle-container-options-icons"></fa-icon>
<!-- <ion-icon name="trash"></ion-icon> -->
</div>
<div class="right" *ngIf="roomType == RoomTypeEnum.Group">
<button class="btn-no-color" (click)="openMessagesOptions()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " src="assets/images/theme/blue/icons-menu.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " src="assets/images/theme/gov/icons-menu.svg">
</ion-icon>
</button>
</div>
</div>
<div class="header-bottom">
<div class="header-bottom-icon" *ngIf="roomType == RoomTypeEnum.Group">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " src="assets/icon/icons-user.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " src="assets/icon/theme/gov/icons-user.svg"></ion-icon>
</div>
<ion-list class="header-bottom-contacts" *ngIf="roomMembers$ | async as memberList" >
<ng-container *ngFor="let user of memberList; let i = index">
<span *ngIf="roomType == RoomTypeEnum.Group"> {{ user.wxFullName }}<ng-container *ngIf="i < memberList.length - 1">, </ng-container> </span>
</ng-container>
</ion-list>
</div>
</div>
</ion-toolbar>
</ion-header>
<ion-content >
<div class="messages height-100 width-100 d-flex flex-column" #scrollMe >
<div
*ngFor="let message of messages1[roomId]; let messageIndex = index" class="messages-list-item-wrapper"
[ngClass]="{
'info-meeting': message.messageType == IMessageType.information && !message.ballon,
'info-ballon': message.ballon == true,
'my-message': message.messageType == IMessageType.normal && message?.sender?.wxUserId === SessionStore.user.UserId && !message.ballon,
'other-message': message.messageType == IMessageType.normal && message?.sender?.wxUserId !== SessionStore.user.UserId && !message.ballon
}"
>
<!-- Emoji Picker -->
<div *ngIf="selectedMessage === message" class="emoji-picker mr-20" [ngStyle]="{'bottom': '0', 'right': '0'}">
<span *ngFor="let emoji of emojis" (click)="addReaction(message, emoji)" class="emoji-icon">
{{ emoji }}
</span>
</div>
<div class="message-container rotate-div" *ngIf="message.showMessage">
<div class="d-flex justify-content-between">
<div>
<div style="white-space: pre-line;">
{{ message.message }}
</div>
<div *ngFor="let attachment of message.attachments; let i = index">
<div *ngIf="attachment.source == MessageAttachmentFileSource.Webtrix">
<ion-icon src="assets/icon/webtrix.svg" class="file-icon font-25"></ion-icon>
<!-- <ion-label>{{ attachment.fileName}}</ion-label> -->
<!-- <ion-icon *ngIf="ThemeService.currentTheme == 'default' && attachment.type != 'webtrix' && !( msg.downloadLoader == true || msg.uploadingFile == true ) " class="icon-download" src="assets/icon/theme/default/icons-download.svg" slot="end"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' && attachment.type != 'webtrix' && !( msg.downloadLoader == true || msg.uploadingFile == true ) " class="icon-download" src="assets/icon/theme/gov/icons-download.svg" slot="end"></ion-icon>
<ion-icon *ngIf="( msg.downloadLoader == true || msg.uploadingFile == true )" class="icon-download" src="assets/gif/theme/{{ThemeService.currentTheme}}/Blocks-loader.svg" slot="end"></ion-icon> -->
</div>
<div *ngIf="attachment.fileType == MessageAttachmentFileType.Image">
<img
*ngIf="message.oneShot != true && attachment.blobURl != true"
[src]="attachment.safeFile"
(load)="onImageLoad(message, messageIndex)"
(error)="onImageError()"
>
<img
*ngIf="message.oneShot != true && attachment.blobURl"
[src]="attachment.safeFile|safehtml"
(load)="onImageLoad(message, messageIndex)"
(error)="onImageError()"
>
<div *ngIf="SessionStore.user.UserId == message.sender.wxUserId && message.oneShot == true">
Mandou uma mensagen com visualização única
</div>
<div *ngIf="SessionStore.user.UserId != message.sender.wxUserId && message.oneShot == true">
<!-- <div *ngIf="message.oneShot == true" class="cursor-pointer"> -->
<div (click)="viewOnce($event, message, i)">
Abrir a visualização única
</div>
</div>
</div>
<div *ngIf="attachment.fileType == MessageAttachmentFileType.Audio">
<audio [src]="attachment.safeFile|safehtml" preload="metadata" class="flex-grow-1" controls controlsList="nodownload noplaybackrate"></audio>
</div>
<div *ngIf="attachment.fileType == MessageAttachmentFileType.Doc" class="d-flex" (click)="openPreview(message)">
<fa-icon *ngIf="attachment.mimeType == 'application/pdf'" icon="file-pdf" class="pdf-icon"></fa-icon>
<fa-icon *ngIf="attachment.mimeType == 'application/word'" icon="file-word" class="word-icon">
</fa-icon>
<fa-icon *ngIf="attachment.mimeType == 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'" icon="file-word" class="word-icon"></fa-icon>
<fa-icon
*ngIf="attachment.mimeType == 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'"
icon="file-word" class="excel-icon"></fa-icon>
<ion-icon *ngIf="attachment.mimeType == 'application/webtrix'" src="assets/icon/webtrix.svg">
</ion-icon>
<ion-icon *ngIf="attachment.mimeType == 'application/meeting'" src="assets/icon/webtrix.svg">
</ion-icon>
<ion-label>{{ attachment?.fileName || attachment?.description }}</ion-label>
</div>
</div>
</div>
<div>
<div class="message-item-options d-flex justify-content-end">
<fa-icon [matMenuTriggerFor]="beforeMenu" icon="chevron-down" class="message-options-icon cursor-pointer"></fa-icon>
<mat-menu class="custom-menu" #beforeMenu="matMenu" xPosition="before">
<button (click)="messageDelete(message)" class="menuButton">Apagar mensagem</button>
<button *ngIf="!message.hasAttachment" (click)="editMessage(message)" class="menuButton">Editar mensagem</button>
<button (click)="toggleEmojiPicker(message)" class="menuButton">Reagir mensagem</button>
</mat-menu>
</div>
</div>
</div>
<div style="text-align: end;">
<div *ngIf="totalMembers != 0 && SessionStore.user.UserId == message.sender.wxUserId">
<ion-icon *ngIf="messageStatus(message) == 'enviar'" src="assets/images/clock-regular.svg"></ion-icon>
<ion-icon *ngIf="messageStatus(message) == 'enviado'" src="assets/images/check-solid.svg"></ion-icon>
<ion-icon *ngIf="messageStatus(message) == 'allReceived'" src="assets/images/check-double-solid.svg"></ion-icon>
<ion-icon *ngIf="messageStatus(message) == 'allViewed'" src="assets/images/check-double-solid -viewed.svg"></ion-icon>
</div>
</div>
</div>
<div class="message-container rotate-div" *ngIf="message.isDeleted == true">
Mensagem foi eliminada
</div>
<div *ngIf="message.messageType == IMessageType.information && !message.ballon" class="text-center">
{{ message.message }}
</div>
<div *ngIf="message.ballon" class="text-center ballon">
{{ message.message }}
</div>
<!-- current emoji -->
<div class="rotate-div emoji-container" *ngIf="message.isDeleted != true && message.messageType != IMessageType.information && message.ballon != true">
<span *ngFor="let reaction of message.reactions" class="emoji-icon">
{{ reaction.reaction }}
</span>
</div>
</div>
<!--
<ion-fab horizontal="end" vertical="bottom" slot="fixed">
<ion-fab-button *ngIf="scrollToBottomBtn" color="light" size="small">
<ion-icon name="chevron-down"></ion-icon>
</ion-fab-button>
</ion-fab> -->
<ion-fab horizontal="start" vertical="bottom" slot="fixed">
<div #array>
</div>
</ion-fab>
<!-- <div *ngIf="userTyping$?.typingList?.typingList">
<div
*ngFor="let message of userTyping$.typingList.typingList " class="messages-list-item-wrapper"
>
{{ message.userName }}
</div>
</div>
-->
<!-- <div *ngIf="userTyping$" class="header-bottom-contacts" >
<div *ngFor="let typing of userTyping$; let i = index">
{{ typing.userName }}<div *ngIf="i < userTyping$.length - 1">, </div>
</div>
</div>
-->
</div>
</ion-content>
<ion-footer>
<!-- <div class="typing" *ngIf="ChatSystemService.getDmRoom(roomId).otherUserType == true">
<ngx-letters-avatar [avatarName]="ChatSystemService.getGroupRoom(roomId).name" [width]="30" [circular]="true"
fontFamily="Roboto"></ngx-letters-avatar>
está a escrever ...
</div> -->
<div class="width-100 pl-20 pr-20">
<span *ngIf="!lastAudioRecorded">{{durationDisplay}}</span>
<audio [src]="audioRecorded" class="d-flex width-100 mt-10 mb-10" *ngIf="lastAudioRecorded" controls
controlsList="nodownload noplaybackrate"></audio>
</div>
<div class="container width-100 d-flex">
<div>
<button *ngIf="!recording && !lastAudioRecorded && allowTyping" class="btn-no-color" (click)="openChatOptions()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-options"
src="assets/images/icons-add.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-options"
src="assets/images/theme/gov/icons-add.svg"></ion-icon>
</button>
<button *ngIf="recording || lastAudioRecorded || !allowTyping" class="btn-no-color" (click)="deleteRecording()">
<fa-icon class="icon-size-27" icon="trash"></fa-icon>
</button>
</div>
<div class="width-70 message-container">
<div *ngIf="!recording && !lastAudioRecorded" class="type-message">
<ion-textarea *ngIf="allowTyping" autocomplete="on" autocorrect="on" spellcheck="true" clearOnEdit="true"
placeholder="Escrever uma mensagem" auto-grow class="message-input" rows="1"
[(ngModel)]="textField"
(ionChange)="sendTyping()"></ion-textarea>
</div>
<div *ngIf="recording" class="d-flex align-items-center justify-content-center">
<button (click)="stopRecording()" class="btn-no-color d-flex align-items-center justify-content-center">
<ion-icon class="icon-size-45" name="stop-circle-outline" color="danger"></ion-icon>
</button>
</div>
</div>
<div>
<button #recordbtn *ngIf="textField == '' && !lastAudioRecorded" (click)="startRecording()" class="btn-no-color">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/default/icons-chat-record-audio.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-record-audio.svg"></ion-icon>
</button>
<button *ngIf="textField != ''" class="btn-no-color" (click)="sendMessage()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button>
<button *ngIf="textField == '' && lastAudioRecorded" class="btn-no-color" (click)="sendAudio(lastAudioRecorded)">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " class="chat-icon-send" src="assets/icon/theme/gov/icons-chat-send.svg"></ion-icon>
</button>
</div>
</div>
</ion-footer>
@@ -0,0 +1,526 @@
@import '~src/function.scss';
@media only screen and (min-width: 100px) {
:host {
font-size: 14px;
}
}
@media only screen and (min-width: 500px) {
:host {
font-size: 16px;
}
}
.header-toolbar {
--background: transparent;
--opacity: 1;
.main-header {
width: 100%;
/* 400px */
height: 100%;
font-family: Roboto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-color: #fff;
overflow: hidden;
padding: 30px 20px 0px 20px;
color: #000;
transform: translate3d(0, 1px, 0);
.header-top {
margin: 0px auto;
overflow: auto;
padding: 0 !important;
background: #fff;
.left {
width: fit-content;
float: left;
//font-size: rem(35);
overflow: hidden;
.header-top-btn {
background: transparent;
font-size: rem(25) !important;
font-weight: 100 !important;
/* color: #0782c9; */
color: #42b9fe;
}
}
.middle-container {
height: auto;
.middle {
padding: 0 !important;
float: left;
width: calc(100% - 77px);
margin: 0px 0 0 10px;
display: flex;
align-items: center;
}
}
.middle-container-options {
padding: 0 !important;
float: left;
width: calc(100% - 25px);
text-align: right;
.middle-container-options-icons {
color: #0782c9;
font-size: rem(23);
}
}
.right {
padding: 0 !important;
float: right;
font-size: rem(25);
color: #0782c9;
margin: 5px 0 0 0;
}
}
.header-bottom {
overflow: auto;
margin: 0 auto;
.header-bottom-icon {
width: rem(30);
font-size: rem(25);
float: left;
padding: 2px;
}
.header-bottom-contacts {
width: 275px;
font-size: rem(15);
color: #797979;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
float: left;
padding: 5px;
margin: 1px;
}
}
.title {
font-size: rem(25);
white-space: nowrap;
overflow: hidden !important;
text-overflow: ellipsis !important;
float: left;
}
.div-icon {
width: rem(40);
float: right;
font-size: rem(35);
overflow: auto;
padding: 1px;
}
.div-icon ion-icon {
float: right;
padding-left: 20px;
}
}
}
ion-content {
.welcome-text {
/* width: 322px; */
width: rem(422);
background: #ebebeb;
text-align: center;
font-size: rem(13);
color: #797979;
padding: 10px;
margin: 0 auto !important;
line-height: 1.2rem;
// margin: 20px 39px 25px;
border-radius: 8px;
}
.messages {
font-size: rem(13);
font-family: Roboto;
overflow: auto;
//set scroll do bottom
position: absolute;
top: 0;
left: 0;
overflow-x: hidden;
overflow-y: auto;
width: 100%;
height: 100%;
word-wrap: break-word;
-webkit-overflow-scrolling: touch;
.messages-list-itrem-wrapper {
overflow: hidden;
}
.messages-list-itrem-wrapper-active {
background: #e6f6ff75 !important;
}
.message-container {
//border: 1px solid red;
}
.incoming-true,
.incoming-false {
width: 305px;
padding: 15px 20px;
border-radius: 10px;
}
.incoming-true {
margin: 10px 35px 10px 20px;
background: #ebebeb;
float: left;
}
}
.incoming-false {
margin: 10px 20px 10px 35px;
background: var(--chat-incoming-msg-color);
float: right;
}
.title {
display: inline;
color: var(--title-text-color);
font-weight: bold;
margin-bottom: 5px;
.time {
color: #797979;
text-align: right;
float: right;
}
}
}
.info-meeting {
/* width: 322px; */
width: rem(422);
background: var(--chat-alert-msg-color);
text-align: center;
font-size: rem(13);
color: #262420;
padding: 10px;
margin: 10px auto;
line-height: 1.2rrem;
/* margin: 15px 0px 15px 0px; */
border-radius: 8px;
.info-meeting-small {
font-size: rem(10);
font-style: italic;
}
.info-meeting-medium {
font-size: rem(12);
}
.info-meeting-normal {
color: #0782c9;
font-weight: 700;
text-decoration: underline;
}
.info-meeting-normal:hover {
text-decoration: underline;
color: #0782c9;
}
}
ion-footer {
padding-top: 7.5px;
padding-bottom: 20px;
.container {
justify-content: center;
justify-content: space-evenly;
align-itrems: center;
}
.chat-icon-options {
display: block !important;
font-size: rem(35);
float: right !important;
margin-top: 5px;
}
.chat-icon-send {
font-size: rem(40);
margin: 0 auto;
margin-top: 4px;
}
.type-message {
display: flex;
border: 1px solid #ebebeb;
border-radius: 25px;
padding-left: 15px;
align-itrems: center;
overflow: auto;
ion-textarea {
margin: 0 !important;
align-self: center;
overflow: auto;
}
}
}
.text-color-blue {
font-size: rem(15);
color: #0782c9;
font-weight: 500;
letter-spacing: normal;
}
.user-status-online {
display: block;
float: left;
color: #99e47b;
padding-left: 10px;
}
.online {
display: block;
float: left;
color: #99e47b;
padding-left: 10px;
}
.offline {
color: #cbced1;
display: block;
float: left;
padding-left: 10px;
}
.away {
color: #ffd21f;
display: block;
float: left;
padding-left: 10px;
}
.invisible {
color: #cbced1;
display: block;
float: left;
padding-left: 10px;
}
.busy {
color: #f5455c;
display: block;
float: left;
padding-left: 10px;
}
.typing {
position: relative;
top: -25px;
height: 0px;
left: 0px;
margin-left: 22px;
display: flex;
font-size: rem(12);
align-itrems: center;
}
.typing ngx-letters-avatar {
padding-right: 5px;
}
button {
padding: 0px;
border: 0px;
}
button::-moz-focus-inner {
padding: 0px;
border: 0px;
}
.float-status {
position: relative !important;
float: right;
display: flex;
align-itrems: self-end;
}
.float-status-image {
position: relative !important;
float: right;
display: flex;
align-itrems: self-end;
top: -15px;
}
.float-status-webtrix {
position: relative !important;
top: 0px !important;
float: right;
display: flex;
align-itrems: self-end;
}
.float-status-all {
font-size: rem(13) !important;
}
.try {
color: red;
background: #f3414159;
padding: 6px;
border-radius: 10px;
cursor: pointer;
}
.font-40-rem {
font-size: 2.5rem !important;
}
.dateLabel {
background: #ebebeb !important;
float: unset !important;
margin: 0px auto !important;
width: 111px !important;
text-align: center;
}
.message-item-options {
position: relative;
}
.emoji-picker {
display: flex;
flex-wrap: wrap;
background: white;
border: 1px solid #ccc;
padding: 5px;
border-radius: 5px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
}
.emoji-icon {
font-size: 20px;
cursor: pointer;
margin: 2px;
}
.messages {
font-size: rem(13);
font-family: Roboto;
overflow: auto;
//set scroll do bottom
// position: absolute;
// top: 0;
// left: 0;
// overflow-x: hidden;
// overflow-y: auto;
// width: 100%;
// height: 100%;
// word-wrap: break-word;
// -webkit-overflow-scrolling: touch;
.other-message,
.my-message {
.message-container {
padding: 15px 20px;
margin: 10px 20px 10px 75px;
background: var(--chat-incoming-msg-color);
border-radius: 10px;
}
}
.other-message {
display: flex;
/* justify-content: flex-end; */
align-items: start;
flex-direction: column;
// float: left;
// Styles for incoming messages from other users
justify-content: flex-start;
.message-container {
padding: 15px 20px;
margin: 10px 75px 10px 20px;
background: #ebebeb;
border-radius: 10px;
}
}
}
.my-message {
display: flex;
/* justify-content: flex-end; */
align-items: end;
flex-direction: column;
}
.info-ballon {
text-align: center;
font-size: rem(13);
color: #262420;
padding: 10px;
margin: 10px auto;
line-height: 2.2rem;
border-radius: 8px;
.ballon {
background: var(--chat-alert-msg-color);
padding: 0px 10px;
border-radius: 8px;
}
}
.emoji-container{
padding: 0px 20px;
/* margin-bottom: -10px; */
position: relative;
top: -10px;
margin-bottom: -15px;
}
.right {
padding: 0 !important;
float: right;
font-size: rem(25);
color: #0782c9;
margin: 5px 0 0 0;
}
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { MessagesPage } from './messages.page';
describe('MessagesPage', () => {
let component: MessagesPage;
let fixture: ComponentFixture<MessagesPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MessagesPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(MessagesPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ContactsPage } from './contacts.page';
const routes: Routes = [
{
path: '',
component: ContactsPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ContactsPageRoutingModule {}
@@ -0,0 +1,25 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { ContactsPageRoutingModule } from './contacts-routing.module';
import { ContactsPage } from './contacts.page';
import { SharedModule } from 'src/app/shared/shared.module';
import { BtnSeguintePageModule } from 'src/app/shared/btn-seguinte/btn-seguinte.module';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
ContactsPageRoutingModule,
BtnSeguintePageModule,
],
declarations: [ContactsPage]
})
export class ContactsPageModule {}
@@ -0,0 +1,57 @@
<ion-header class="ion-no-border">
<ion-toolbar class="header-toolbar">
<div class="main-header">
<div class="title-content width-100">
<div class="back-icon">
<button class="btn-no-color cursor-pointer" (click)="close()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="end" src='assets/images/icons-arrow-arrow-left.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'doneIt' " src="assets/images/theme/doneIt/icons-calendar-arrow-left.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="end" src='assets/images/theme/gov/icons-calendar-arrow-left.svg'></ion-icon>
</button>
</div>
<div class="div-title">
<ion-label class="title">Contactos</ion-label>
</div>
<app-btn-seguinte (click)="groupMessages()" class="cursor-pointer"></app-btn-seguinte>
</div>
</div>
</ion-toolbar>
<ion-toolbar class="toolbar-search">
<div class="search">
<ion-searchbar search-icon="undefined" (ionChange)="onChange($event)" placeholder="Pesquisar por contacto" ></ion-searchbar>
</div>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-refresher name="refresher" slot="fixed" (ionRefresh)="doRefresh($event)">
<ion-progress-bar type="indeterminate" *ngIf="showLoader"></ion-progress-bar>
<ion-refresher-content>
</ion-refresher-content>
</ion-refresher>
<div class="main-content">
<!-- <ion-list>
<ion-item *ngFor="let user of searchedItem">
{{user.name}}
</ion-item>
</ion-list> -->
<ion-virtual-scroll [items]="users" approxItemHeight="70px" [headerFn]="separateLetter">
<div class="item-divider" *virtualHeader="let header">
<ion-label>{{header}}</ion-label>
</div>
<div *virtualItem="let user" class="item-checkbox">
<ion-checkbox color="primary"></ion-checkbox>
<p>{{user.first}} {{user.last}}</p>
<ion-icon name="ellipse"></ion-icon>
</div>
</ion-virtual-scroll>
</div>
</ion-content>
@@ -0,0 +1,128 @@
@import '~src/function.scss';
.header-toolbar{
--background:transparent;
--opacity: 1;
.main-header{
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-color: #fff;
overflow:hidden;
padding: 30px 20px 0px 20px;
color:#000;
transform: translate3d(0, 1px, 0);
.div-icon{
width: rem(40);
float: right;
font-size: rem(35);
overflow: auto;
padding: 1px;
}
.div-icon ion-icon{
float: right;
padding-left: 20px;
}
.title-content{
margin: 0px auto;
overflow: auto;
padding: 0 !important;
}
.back-icon{
width: 37px;
float: left;
font-size: rem(35);
overflow: auto;
}
.div-title{
width: 221px;
padding: 0!important;
float: left;
margin: 2.5px 0 0 5px;
}
.title{
font-size: rem(25);
}
}
}
.toolbar-search{
--padding-top:0 !important;
--padding-bottom:0 !important;
--padding-start:0 !important;
--padding-end:0 !important;
.search{
border: 1px solid #ebebeb;
margin: 5px 20px 5px 20px;
border-radius: 5px;
}
.search ion-searchbar{
/* border: 1px solid green; */
width: 100%;
margin: 0 !important;
padding: 0 !important;
--border-radius: 5px;
--box-shadow: none;
overflow: auto;
--icon-color:var(--title-text-color);
}
}
ion-content{
--background:transparent;
}
.main-content{
width: 100%;
height: 100%;
font-family: Roboto;
margin: 0 auto;
background-color: #fff;
overflow:auto;
padding: 0 0 0 0;
.item-divider{
background: #ebebeb;
font-size: rem(15);
margin: 10px 0 10px 0;
padding:5px 0 5px 20px;
}
.item-checkbox{
display: flex;
margin: 10px 20px 10px 20px !important;
overflow: auto;
align-items: center;
}
.item-checkbox ion-checkbox{
--border-color: var(--title-text-color);
--background-checked:var(--title-text-color);
float: left;
}
.item-checkbox p{
display: block;
margin: 0 !important;
width: 330px;
padding-left: 10px;
font-size: rem(15);
color: var(--title-text-color);
float: left;
}
.item-checkbox ion-icon{
font-size: rem(10);
float: left;
color:#99e47b;
margin-left: 10px;
}
}
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { ContactsPage } from './contacts.page';
describe('ContactsPage', () => {
let component: ContactsPage;
let fixture: ComponentFixture<ContactsPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ContactsPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(ContactsPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,120 @@
import { HttpHeaders } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { GroupMessagesPage } from '../../group-messages/group-messages.page';
import { ThemeService } from 'src/app/services/theme.service'
@Component({
selector: 'app-contacts',
templateUrl: './contacts.page.html',
styleUrls: ['./contacts.page.scss'],
})
export class ContactsPage implements OnInit {
showLoader: boolean;
users = [];
contact: string[] = [" Ana M.", "Andre F.", "Bruno G.", "Catarina T", "Tiago"];
headers: HttpHeaders;
options:any;
contacts = [
{
first: 'Ana',
last: 'Manuel',
url: 'https://randomuser.me/api/portraits/med/women/54.jpg',
},
{
first: 'Abdullah',
last: 'Hill',
url: 'https://randomuser.me/api/portraits/med/women/54.jpg',
},
{
first: 'Batur',
last: 'Oymen',
url: 'https://randomuser.me/api/portraits/med/women/54.jpg',
},
{
first: 'Bianca',
last: 'Costa',
url: 'https://randomuser.me/api/portraits/med/women/54.jpg',
},
{
first: 'Zaya',
last: 'Mary',
url: 'https://randomuser.me/api/portraits/med/women/54.jpg',
},
{
first: 'Tiago',
last: 'Kayaya',
url: 'https://randomuser.me/api/portraits/med/women/54.jpg',
}
];
constructor(
private modalController: ModalController,
public ThemeService: ThemeService
)
{ }
ngOnInit() {
this.loadUsers();
}
loadUsers(){
this.users = this.contacts.sort((a,b) => {
if(a.first < b.first){
return -1;
}
if(a.first > b.first){
return 1;
}
return 0;
});
}
separateLetter(record, recordIndex, records){
if(recordIndex == 0){
return record.first[0];
}
let first_prev = records[recordIndex - 1].first[0];
let first_current = record.first[0];
if(first_prev != first_current){
return first_current;
}
return null;
}
doRefresh(event){
}
close(){
this.modalController.dismiss();
}
onChange(event){
}
clicked(){
}
async groupMessages(){
const modal = await this.modalController.create({
component: GroupMessagesPage,
componentProps: {},
cssClass: 'contacts',
backdropDismiss: false
});
modal.onDidDismiss();
await modal.present();
}
}
@@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { NewGroupPage } from './new-group.page';
const routes: Routes = [
{
path: '',
component: NewGroupPage
},
{
path: 'contacts',
loadChildren: () => import('./contacts/contacts.module').then( m => m.ContactsPageModule)
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class NewGroupPageRoutingModule {}
@@ -0,0 +1,25 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { NewGroupPageRoutingModule } from './new-group-routing.module';
import { NewGroupPage } from './new-group.page';
import { SharedModule } from 'src/app/shared/shared.module';
import { BtnSeguintePageModule } from 'src/app/shared/btn-seguinte/btn-seguinte.module';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
NewGroupPageRoutingModule,
BtnSeguintePageModule,
],
declarations: [NewGroupPage]
})
export class NewGroupPageModule {}
@@ -0,0 +1,47 @@
<ion-header class="ion-no-border">
<ion-toolbar class="header-toolbar">
<div class="main-header">
<div class="title-content width-100">
<div class="left">
<button class="btn-no-color" (click)="close()">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="end" src='assets/images/icons-arrow-arrow-left.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'doneIt' " src="assets/images/theme/doneIt/icons-calendar-arrow-left.svg"></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="end" src='assets/images/theme/gov/icons-calendar-arrow-left.svg'></ion-icon>
</button>
</div>
<div class="middle">
<ion-label class="title">Novo Grupo</ion-label>
</div>
<div *ngIf="groupName">
<button class="btn-no-color btn-criar" (click)="createGroup()">
<ion-label>Criar grupo</ion-label>
</button>
</div>
</div>
</div>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="main-content">
<div class="item-container">
<ion-input [(ngModel)]="groupName" placeholder="Título"></ion-input>
</div>
<div class="item-container-no-border">
<ion-checkbox (ionChange)="_ionChange($event)" color="primary"></ion-checkbox>
<ion-label>Grupo Ultra-secreto</ion-label>
</div>
<div *ngIf="showDuration" class="container-div">
<div class="ion-item-class-2 width-100">
<div class="ion-icon-class">
<ion-icon slot="start" src="assets/images/icons-duration.svg"></ion-icon>
</div>
<div class="ion-input-class">
<ion-input (click)="showPicker()" [(ngModel)]="displayDuration" placeholder="Duração"></ion-input>
</div>
</div>
</div>
</div>
</ion-content>
@@ -0,0 +1,157 @@
@import '~src/function.scss';
ion-content{
--background:transparent;
}
.header-toolbar{
--background:transparent;
--opacity: 1;
}
.div-top-header{
width: 400px;
margin: 0 auto;
background-color: #0782c9;
overflow: auto;
padding-top: 15px;
border: 0!important;
.div-search{
font-size: rem(45);
float: left;
margin: 0 0 0 10px
}
.div-logo{
background: transparent;
width: 140px;
margin: 5px 0 0px 71px;
float: left;
}
.div-logo img{
width: 100%;
}
.div-profile{
font-size: rem(45);
float: right;
margin-right: 10px;
}
}
.main-header{
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-color: #fff;
overflow:hidden;
padding: 30px 20px 0px 20px;
color:#000;
transform: translate3d(0, 1px, 0);
.title-content{
margin: 0px auto;
overflow: auto;
padding: 0 !important;
background: #fff;
.left{
width: 37px;
float: left;
font-size: rem(35);
overflow: auto;
}
.middle{
padding: 0!important;
float: left;
width:fit-content;
margin: 2.5px 0 0 5px;
}
.btn-criar{
padding: 0!important;
float: right;
font-size: rem(15);
color: var(--font-awesome);
margin: 8px 5px 0 5px;
}
.right{
padding: 0!important;
float: right;
font-size: rem(15);
color: #0782c9;
margin: 8px 0 0 5px;
}
}
.title{
font-size: rem(25);
}
.div-icon{
width: rem(40);
float: right;
font-size: rem(35);
overflow: auto;
padding: 1px;
}
.div-icon ion-icon{
float: right;
padding-left: 20px;
}
}
.main-content{
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
margin: 0 auto;
background-color: #fff;
overflow:auto;
padding: 15px 20px 0 20px;
.item-container{
margin: 15px auto;
border: 1px solid #ebebeb;
border-radius: 5px;
padding-left: 10px;
}
.item-container-no-border{
display: flex;
margin: 25px auto;
border-radius: 5px;
align-items: center;
}
.item-container-no-border ion-label{
padding-left: 10px;
font-size: rem(12);
color: #000;
}
}
.container-div{
margin-bottom: 15px;
overflow: auto;
.ion-item-class-2{
margin: 0px auto;
overflow: auto;
.ion-icon-class{
width: rem(45);
height: rem(45);
float: left;
padding: 10px;
font-size: rem(25);
}
}
.ion-input-class{
width: calc(100% - 45px) !important;
height: rem(45);
border: 1px solid #ebebeb;
border-radius: 5px;
padding-left: 5px;
padding-right: 10px;
float: left;
}
}
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { NewGroupPage } from './new-group.page';
describe('NewGroupPage', () => {
let component: NewGroupPage;
let fixture: ComponentFixture<NewGroupPage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ NewGroupPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(NewGroupPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,338 @@
import { Component, OnInit } from '@angular/core';
import { ModalController, NavParams, PickerController, PopoverController } from '@ionic/angular';
import { GroupDurationPage } from 'src/app/shared/popover/group-duration/group-duration.page';
import { GroupContactsPage } from '../group-messages/group-contacts/group-contacts.page';
import { ThemeService } from 'src/app/services/theme.service';
import { SessionStore } from 'src/app/store/session.service';
import { ToastService } from 'src/app/services/toast.service';
import { catchError } from 'rxjs/operators';
@Component({
selector: 'app-new-group',
templateUrl: './new-group.page.html',
styleUrls: ['./new-group.page.scss'],
})
export class NewGroupPage implements OnInit {
isGroupCreated: boolean;
showLoader: boolean;
displayDuration: any;
showDuration: boolean;
selectedDuration = ['', '', ''];
thedate: any;
groupName: string;
documents: any;
loggedUserChat: any;
constructor(
private pickerController: PickerController,
private popoverController: PopoverController,
private modalController: ModalController,
private navParams: NavParams,
public ThemeService: ThemeService,
// public ChatSystemService: ChatSystemService,
private toastService: ToastService,
) {
this.loggedUserChat = SessionStore.user.ChatData['data'];
this.isGroupCreated = false;
this.groupName = this.navParams.get('name');
this.documents = this.navParams.get('documents');
}
ngOnInit() {
// this.chatService.refreshtoken();
// console.log(this.documents)
}
_ionChange(event) {
this.showDuration = event.detail.checked;
if (event.detail.checked) {
this.thedate = new Date();
}
else {
this.thedate = '';
}
}
close() {
this.modalController.dismiss();
}
async createGroup() {
// let name = this.groupName.split(' ').join('-');
// //Take out all special characters in string
// name = name.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
// let customFields = {}
// let res: any;
// if(!SessionStore.user?.ChatData?.data) {
// this.toastService._successMessage("Chat temporariamente indisponível")
// }
// try {
// if (this.thedate) {
// let customFields = {
// "countDownDate": this.thedate
// }
// res = await this.ChatSystemService.createPrivateRoom(name, SessionStore.user.UserName, customFields);
// }
// else {
// res = await this.ChatSystemService.createPrivateRoom(name, SessionStore.user.UserName, customFields);
// }
// try {
// this.isGroupCreated = true;
// this.addContacts(res.result);
// this.ChatSystemService.getRoom([res.result]);
// setTimeout(() => {
// this.ChatSystemService.subscribeToRoomUpdate(res.result.rid, res.result);
// }, 10)
// } catch (error) {
// await this.ChatSystemService.getUser();
// await this.ChatSystemService.getAllRooms();
// await this.ChatSystemService.subscribeToRoom();
// this.isGroupCreated = true;
// this.addContacts(res.result);
// this.ChatSystemService.getRoom([res.result]);
// setTimeout(() => {
// this.ChatSystemService.subscribeToRoomUpdate(res.result.rid, res.result);
// }, 10)
// }
// if (res?.result?.rid) {
// this.ChatSystemService.getAllRooms(() => {
// if (!this.ChatSystemService.getGroupRoom(res.result.rid)) {
// this.createGroupWithAttachmentsCath(res)
// } else {
// setTimeout(() => {
// this.createGroupWithAttachments(res)
// }, 500)
// }
// }, res.result.rid);
// } else {
// this.toastService._badRequest('Existe um grupo com este nome!');
// }
// } catch(error) {
// this.toastService._successMessage("Chat temporariamente indisponível")
// }
}
createGroupWithAttachmentsCath(res: any) {
// if (!this.ChatSystemService.getGroupRoom(res.result.rid)) {
// setTimeout(() => {
// this.createGroupWithAttachmentsCath(res)
// }, 1500)
// } else {
// this.createGroupWithAttachments(res)
// }
}
createGroupWithAttachments(res: any) {
// this.ChatSystemService.getGroupRoom(res.result.rid).hasLoadHistory = true;
// if (this.documents) {
// this.documents.forEach(element => {
// this.ChatSystemService.getGroupRoom(res.result.rid).send({
// file: {
// "name": element.Assunto,
// "type": "application/webtrix",
// "ApplicationId": element.ApplicationId,
// "DocId": element.DocId,
// "Assunto": element.Assunto,
// },
// temporaryData: {
// data: {
// selected: {
// Id: element.DocId,
// ApplicationType: element.ApplicationId
// }
// }
// },
// attachments: [{
// "title": element.Assunto,
// "description": element.Assunto,
// "title_link_download": true,
// "type": "webtrix",
// "text": element.Assunto,
// "thumb_url": "https://static.ichimura.ed.jp/uploads/2017/10/pdf-icon.png",
// }],
// })
// });
// }
// this.ChatSystemService.getAllRooms();
// setTimeout(() => {
// this.groupName = ""
// }, 150);
}
async addContacts(room) {
this.close();
let name = this.groupName.split(' ').join('-');
const modal = await this.modalController.create({
component: GroupContactsPage,
componentProps: {
room: room,
},
cssClass: 'contacts',
backdropDismiss: false
});
modal.onDidDismiss();
await modal.present();
}
async setDuration(ev: any) {
const popover = await this.popoverController.create({
component: GroupDurationPage,
cssClass: 'group-duration',
event: ev,
translucent: true
});
return await popover.present();
}
async showPicker() {
const picker = await this.pickerController.create({
cssClass: '',
buttons: [
{
text: 'Cancelar', role: 'cancel', cssClass: 'btn-cancel'
},
{
text: 'Ok',
cssClass: 'btn-cancel',
handler: (value: any) => {
let now = new Date();
this.thedate = new Date(now.getFullYear(), now.getMonth(), now.getDate() + value.days.value, now.getHours() + value.hours.value, now.getMinutes() + value.minutes.value, now.getSeconds(), now.getMilliseconds());
this.selectedDuration = [
value.days.value,
value.hours.value,
value.minutes.value,
]
if (value.days.value != null && value.hours.value != null && value.minutes.value != null) {
if (value.days.value > 0) {
if (value.days.value == 1) {
if (value.hours.value == 1) {
this.displayDuration = value.days.value + " day " +
value.hours.value + " hora " +
value.minutes.value + " minutos";
}
else {
this.displayDuration = value.days.value + " days " +
value.hours.value + " horas " +
value.minutes.value + " minutos";
}
}
else {
if (value.hours.value == 1) {
this.displayDuration = value.days.value + " days " +
value.hours.value + " hora " +
value.minutes.value + " minutos";
}
else {
this.displayDuration = value.days.value + " days " +
value.hours.value + " horas " +
value.minutes.value + " minutos";
}
}
}
else {
if (value.hours.value == 1) {
this.displayDuration = value.hours.value + " hora " +
value.minutes.value + " minutos";
}
else {
this.displayDuration = value.hours.value + " horas " +
value.minutes.value + " minutos";
}
}
}
},
},
],
columns: [
{
name: 'days',
prefix: 'Dias',
options: [
{ text: '0', value: 0 },
{ text: '1', value: 1 },
{ text: '2', value: 2 },
{ text: '3', value: 3 },
{ text: '4', value: 4 },
]
},
{
name: 'hours',
prefix: 'Horas',
options: [
{ text: '0', value: 0 },
{ text: '1', value: 1 },
{ text: '2', value: 2 },
{ text: '3', value: 3 },
{ text: '4', value: 4 },
{ text: '5', value: 5 },
{ text: '6', value: 6 },
{ text: '7', value: 7 },
{ text: '8', value: 8 },
]
},
{
name: 'minutes',
prefix: 'Minutos',
selectedIndex: 0,
options: [
{ text: '5', value: 5 },
{ text: '10', value: 10 },
{ text: '15', value: 15 },
{ text: '20', value: 20 },
{ text: '25', value: 25 },
{ text: '30', value: 30 },
{ text: '35', value: 35 },
{ text: '45', value: 45 },
{ text: '50', value: 50 },
{ text: '55', value: 55 },
]
}
]
});
await picker.present();
picker.onDidDismiss().then(async data => {
let day = await picker.getColumn('days');
let hour = await picker.getColumn('hours');
let minutes = await picker.getColumn('minutes');
});
}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { RoomInfoPage } from './room-info.page';
const routes: Routes = [
{
path: '',
component: RoomInfoPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class RoomInfoPageRoutingModule {}
@@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { RoomInfoPageRoutingModule } from './room-info-routing.module';
import { RoomInfoPage } from './room-info.page';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
RoomInfoPageRoutingModule
],
declarations: [RoomInfoPage]
})
export class RoomInfoPageModule {}
@@ -0,0 +1,22 @@
<ion-header>
<ion-toolbar>
<ion-title class="title" *ngIf="roomData$ | async as roomData"> {{ roomData.roomName }}</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="px-20">
<div class=px-20> Membros </div>
<ion-list class="header-bottom-contacts px-20" *ngIf="roomMembers$ | async as memberList">
<div *ngFor="let user of memberList; let i = index">
<div class="py-1 d-flex align-center">
<div class="image-container mr-10">
<img *ngIf="ObjectURL[user.wxUserId]" [src]="ObjectURL[user.wxUserId]">
</div>
{{ user.wxFullName }} <span class="admin" *ngIf="user.isAdmin">(admin do group)</span>
</div>
</div>
</ion-list>
</ion-content>
@@ -0,0 +1,22 @@
img {
background-color: gray;
border-radius: 20px;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
-ms-border-radius: 20px;
-o-border-radius: 20px;
height: 35px;
width: 35px;
object-fit: cover;
}
.image-container {
height: 35px;
width: 35px;
background-color: gray;
border-radius: 20px;
}
.admin {
color: gray;
}
@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { RoomInfoPage } from './room-info.page';
describe('RoomInfoPage', () => {
let component: RoomInfoPage;
let fixture: ComponentFixture<RoomInfoPage>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ RoomInfoPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(RoomInfoPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,56 @@
import { Component, OnInit } from '@angular/core';
import { NavParams } from '@ionic/angular';
import { Observable } from 'rxjs';
import { MemberListLocalRepository } from 'src/app/module/chat/data/repository/member/member-list-local-repository.service'
import { RoomLocalRepository } from 'src/app/module/chat/data/repository/room/room-local-repository.service'
import { RoomTable } from 'src/app/infra/database/dexie/instance/chat/schema/room';
import { map, tap } from 'rxjs/operators';
import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service'
import { MemberEntity } from 'src/app/core/chat/entity/member';
@Component({
selector: 'app-room-info',
templateUrl: './room-info.page.html',
styleUrls: ['./room-info.page.scss'],
})
export class RoomInfoPage implements OnInit {
roomId:string;
roomMembers$: Observable<MemberEntity[]>
roomData$: Observable<RoomTable | undefined>
ObjectURL : {[key: string]: string} = {};
constructor(
private navParams: NavParams,
private MemberListLocalRepository: MemberListLocalRepository,
private RoomLocalRepository: RoomLocalRepository,
private ChatServiceService: ChatServiceService
) {
this.roomId = this.navParams.get('roomId');
}
ngOnInit() {
// this.roomMessage$ = this.messageRepositoryService.getItemsLive(this.roomId)
this.roomMembers$ = this.MemberListLocalRepository.getRoomMemberByIdLive(this.roomId).pipe(
map((memberList) => memberList.map(e => Object.assign(new MemberEntity(), e))),
tap((members) => {
for(let member of members) {
if(!this.ObjectURL[member.wxUserId] && member.hasPhoto()) {
this.ChatServiceService.getUserPhoto({wxUserId: member.wxUserId, attachmentId: member.userPhoto}).then((result)=> {
if(result.isOk()) {
console.log('get photo', result.value)
this.ObjectURL[member.wxUserId] = 'data:image/jpeg;base64,'+result.value
}
})
}
}
}),
)
this.roomData$ = this.RoomLocalRepository.getRoomByIdLive(this.roomId)
}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { SetRoomOwnerPage } from './set-room-owner.page';
const routes: Routes = [
{
path: '',
component: SetRoomOwnerPage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class SetRoomOwnerPageRoutingModule {}
@@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { SetRoomOwnerPageRoutingModule } from './set-room-owner-routing.module';
import { SetRoomOwnerPage } from './set-room-owner.page';
import { PipesModule } from 'src/app/pipes/pipes.module';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
PipesModule,
SetRoomOwnerPageRoutingModule
],
declarations: [SetRoomOwnerPage]
})
export class SetRoomOwnerPageModule {}
@@ -0,0 +1,45 @@
<ion-header class="ion-no-border">
<ion-toolbar class="header-toolbar">
<div class="main-header">
<div class="title-content width-100">
<div class="back-icon">
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="end" src='assets/images/Theme/doneIt/icons-arrow-arrow-left.svg'></ion-icon>
<button class="btn-no-color cursor-pointer" (click)="close()">
<ion-icon *ngIf="ThemeService.currentTheme == 'doneIt' " slot="end" src='assets/images/theme/{{ThemeService.currentTheme}}/icons-arrow-arrow-left.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'default' " slot="end" src='assets/images/icons-arrow-arrow-left.svg'></ion-icon>
<ion-icon *ngIf="ThemeService.currentTheme == 'gov' " slot="end" src='assets/images/theme/gov/icons-calendar-arrow-left.svg'></ion-icon>
</button>
</div>
<div class="div-title">
<ion-label class="title">Nomear novo administrador</ion-label>
</div>
</div>
</div>
</ion-toolbar>
<ion-toolbar class="toolbar-search">
<div class="search">
<ion-searchbar search-icon="undefined" debounce="500" (ionChange)="onChange($event)" placeholder="Pesquisar por contacto" ></ion-searchbar>
</div>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="main-content" *ngIf="roomMembers$ | async as memberList">
<ion-virtual-scroll [items]="memberList | filter:textSearch: 'wxFullName'" approxItemHeight="70px" [headerFn]="separateLetter">
<div class="item-divider" *virtualHeader="let header">
<ion-label>{{header}}</ion-label>
</div>
<div *virtualItem="let user" class="item-checkbox">
<div class="cursor-pointer d-flex width-100" (click)="setRoomOwner(user)" (ionChange)="setRoomOwner(user)">
<p class="flex-1">{{user.wxFullName}}</p>
<ion-icon slot="end" class="{{user.status}}" name="ellipse"></ion-icon>
</div>
</div>
</ion-virtual-scroll>
</div>
</ion-content>
@@ -0,0 +1,166 @@
@import '~src/function.scss';
.header-toolbar{
--background:transparent;
--opacity: 1;
.main-header{
width: 100%; /* 400px */
height: 100%;
font-family: Roboto;
border-top-left-radius: 25px;
border-top-right-radius: 25px;
background-color: #fff;
overflow:hidden;
padding: 30px 20px 0px 20px;
color:#000;
transform: translate3d(0, 1px, 0);
.div-icon{
width: rem(40);
float: right;
font-size: rem(35);
overflow: auto;
padding: 1px;
}
.div-icon ion-icon{
float: right;
padding-left: 20px;
}
.title-content{
margin: 0px auto;
overflow: auto;
padding: 0 !important;
}
.back-icon{
width: 37px;
float: left;
font-size: rem(35);
overflow: auto;
}
.div-title{
width: calc(100% - 45px);
padding: 0!important;
float: left;
margin: 2.5px 0 0 5px;
}
.title{
font-size: rem(25);
}
}
}
.toolbar-search{
--padding-top:0 !important;
--padding-bottom:0 !important;
--padding-start:0 !important;
--padding-end:0 !important;
.search{
border: 1px solid #ebebeb;
margin: 5px 20px 5px 20px;
border-radius: 5px;
}
.search ion-searchbar{
/* border: 1px solid green; */
width: 100%;
margin: 0 !important;
padding: 0 !important;
--border-radius: 5px;
--box-shadow: none;
overflow: auto;
--icon-color: var(--font-awesome);
}
}
ion-content{
--background:transparent;
}
.main-content{
width: 100%;
height: 100%;
font-family: Roboto;
margin: 0 auto;
background-color: #fff;
overflow:auto;
padding: 0 0 0 0;
.members-label{
margin: 10px 20px 10px 20px !important;
/* font-size: rem(15); */
font-weight: bold;
}
.members-checkbox{
display: flex;
margin: 0px 20px 0px 20px !important;
overflow: auto;
align-items: center;
border-bottom: 1px solid #ebebeb;
}
.members-options{
margin: 0px 20px 0px 19px !important;
overflow: auto;
}
.item-divider{
background: #ebebeb;
font-size: rem(15);
margin: 10px 0 10px 0;
padding:5px 0 5px 20px;
}
.item-checkbox{
display: flex;
margin: 10px 20px 10px 20px !important;
overflow: auto;
align-items: center;
overflow: auto;
}
.members-checkbox ion-checkbox{
--border-color: var(--title-text-color);
--background-checked:var(--title-text-color);
float: left;
}
.item-checkbox ion-checkbox{
--border-color: var(--title-text-color);
--background-checked:var(--title-text-color);
float: left;
}
.item-checkbox p, .members-checkbox p{
display: block;
margin: 0 !important;
padding-left: 10px;
font-size: rem(15);
color: var(--title-text-color);
float: left;
}
.item-checkbox ion-icon, .members-checkbox ion-icon{
font-size: rem(10);
float: left;
color:#99e47b;
margin-left: 10px;
}
.online{
color:#99e47b !important;
}
.offline{
color:#cbced1 !important;
}
.away{
color:#ffd21f !important;
}
.invisible{
color:#cbced1 !important;
}
.busy{
color:#f5455c !important;
}
}
@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { IonicModule } from '@ionic/angular';
import { SetRoomOwnerPage } from './set-room-owner.page';
describe('SetRoomOwnerPage', () => {
let component: SetRoomOwnerPage;
let fixture: ComponentFixture<SetRoomOwnerPage>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ SetRoomOwnerPage ],
imports: [IonicModule.forRoot()]
}).compileComponents();
fixture = TestBed.createComponent(SetRoomOwnerPage);
component = fixture.componentInstance;
fixture.detectChanges();
}));
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,79 @@
import { Component, OnInit } from '@angular/core';
import { ModalController, NavParams } from '@ionic/angular';
;
import { ThemeService } from 'src/app/services/theme.service'
import { ToastService } from 'src/app/services/toast.service';
import { Observable as DexieObservable } from 'Dexie';
import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service';
import { MemberListLocalRepository } from 'src/app/module/chat/data/repository/member/member-list-local-repository.service'
import { MemberTable } from 'src/app/infra/database/dexie/instance/chat/schema/members';
@Component({
selector: 'app-set-room-owner',
templateUrl: './set-room-owner.page.html',
styleUrls: ['./set-room-owner.page.scss'],
})
export class SetRoomOwnerPage implements OnInit {
textSearch:string = "";
roomId:any;
members:any;
roomMembers$!: DexieObservable<MemberTable[] | undefined>
constructor(
private modalController: ModalController,
private navParams: NavParams,
public ThemeService: ThemeService,
private toastService: ToastService,
private chatServiceService: ChatServiceService,
private MemberListLocalRepository: MemberListLocalRepository
) {
this.roomId = this.navParams.get('roomId');
this.members = this.navParams.get('members');
}
ngOnInit() {
// this.chatService.refreshtoken();
this.roomMembers$ = this.MemberListLocalRepository.getRoomMemberNoneAdminByIdLive(this.roomId) as any
}
async close() {
this.modalController.dismiss();
}
onChange(event: any) {
this.textSearch = event.detail.value;
}
separateLetter(record:MemberTable, recordIndex: number, records:MemberTable[]) {
if(recordIndex == 0){
return record.wxFullName[0];
}
let first_prev = records[recordIndex - 1].wxFullName[0];
let first_current = record.wxFullName[0];
if(first_prev != first_current){
return first_current;
}
return null;
}
async setRoomOwner(user:MemberTable) {
const result = await this.chatServiceService.setAdmin({
roomId: user.roomId,
memberId: user.wxUserId.toString()
});
if(result.isOk()) {
this.chatServiceService.getRoomById(this.roomId);
// this.modalController.dismiss('success');
} else {
this.toastService._badRequest('Não foi possível completar a ação, por favor tente novamente.');
}
}
}
@@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { ViewOncesImagePage } from './view-onces.page';
const routes: Routes = [
{
path: '',
component: ViewOncesImagePage
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class ViewOncesPageRoutingModule {}
@@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { ViewOncesPageRoutingModule } from './view-onces-routing.module';
import { ViewOncesImagePage } from './view-onces.page';
import { PipesModule } from 'src/app/pipes/pipes.module';
@NgModule({
imports: [
CommonModule,
FormsModule,
IonicModule,
ViewOncesPageRoutingModule,
PipesModule
],
declarations: [ViewOncesImagePage]
})
export class ViewOncesPageModule {}
@@ -0,0 +1,24 @@
<ion-header>
<ion-toolbar class="d-flex justify-space-between">
<ion-title>Vizualização única</ion-title>
<ion-buttons slot="end">
<ion-button (click)="closePage()" fill="clear">
<ion-icon name="close"></ion-icon>
</ion-button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<div class="justify-center align-center d-flex width-100 height-100">
<img
*ngIf="blobURl"
[src]="params.imageDataUrl|safehtml"
>
<img
*ngIf="!blobURl"
[src]="params.imageDataUrl"
>
</div>
</ion-content>

Some files were not shown because too many files have changed in this diff Show More