mirror of
https://code.equilibrium.co.ao/ITO/doneit-web.git
synced 2026-04-18 12:37:53 +00:00
fix publication
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
# 📅 6-Month LinkedIn Content Calendar for Peter (Full-Stack Developer)
|
||||
|
||||
This is a practical roadmap to grow your visibility and influence on LinkedIn.
|
||||
|
||||
---
|
||||
|
||||
## 🌍 LinkedIn Fame Roadmap
|
||||
|
||||
### Phase 1 – Foundation (Weeks 1–2)
|
||||
- Optimize profile (photo, banner, headline, about, featured projects).
|
||||
- Follow 100+ relevant devs, recruiters, and companies.
|
||||
|
||||
### Phase 2 – Consistency (Weeks 3–6)
|
||||
- Post 3–4 times per week.
|
||||
- Share lessons, demos, explainers, and personal wins.
|
||||
- Engage with other posts.
|
||||
|
||||
### Phase 3 – Authority Building (Months 2–4)
|
||||
- Write long-form articles (e.g., offline-first, clean architecture).
|
||||
- Share diagrams, benchmarks, and tutorials.
|
||||
- Start a content series.
|
||||
|
||||
### Phase 4 – Expansion (Months 4–6)
|
||||
- Collaborate with other devs.
|
||||
- Speak in webinars or podcasts.
|
||||
- Share across GitHub, Dev.to, Medium.
|
||||
|
||||
### Phase 5 – Thought Leadership (Months 6+)
|
||||
- Release libraries/tools.
|
||||
- Do live coding sessions.
|
||||
- Mentor juniors, share insights.
|
||||
|
||||
---
|
||||
|
||||
# 📅 Content Calendar
|
||||
|
||||
## Month 1 – Kickoff & Personal Branding
|
||||
**Goal**: Introduce yourself and build recognition.
|
||||
|
||||
- **Week 1**:
|
||||
- Intro post: “I’m Peter, a full-stack dev passionate about scalable apps & clean architecture.”
|
||||
- Share your tech stack (Angular, Node.js, Redis, RabbitMQ, OpenTelemetry, Nginx).
|
||||
|
||||
- **Week 2**:
|
||||
- Story: “How I solved a 5GB+ file upload challenge.”
|
||||
- Quick explainer: “What is distributed tracing & why should devs care?”
|
||||
|
||||
- **Week 3**:
|
||||
- Share a coding tip from your daily work.
|
||||
- Comment on trending dev posts.
|
||||
|
||||
- **Week 4**:
|
||||
- Failure story: “I misconfigured Nginx SSL once, here’s the lesson.”
|
||||
- Diagram: “Reverse proxy explained in 30 seconds.”
|
||||
|
||||
---
|
||||
|
||||
## Month 2 – Technical Authority
|
||||
**Goal**: Show deep technical knowledge.
|
||||
|
||||
- **Week 1**:
|
||||
- Article: “Offline-first architecture in Angular.”
|
||||
- LinkedIn summary post linking to article.
|
||||
|
||||
- **Week 2**:
|
||||
- Redis vs. DB caching.
|
||||
- Code snippet with before/after perf gain.
|
||||
|
||||
- **Week 3**:
|
||||
- Diagram: RabbitMQ message flow.
|
||||
- Debugging queue bottleneck tip.
|
||||
|
||||
- **Week 4**:
|
||||
- OpenTelemetry case: “Frontend + Backend performance tracing.”
|
||||
- Engage with 10 influencers’ posts.
|
||||
|
||||
---
|
||||
|
||||
## Month 3 – Visibility Boost
|
||||
**Goal**: Grow network and reach.
|
||||
|
||||
- **Week 1**:
|
||||
- Series: “Clean Architecture in Practice (Part 1: Principles).”
|
||||
- Share a GitHub repo demo.
|
||||
|
||||
- **Week 2**:
|
||||
- Poll: Biggest scaling pain?
|
||||
- Humor/meme about dev life.
|
||||
|
||||
- **Week 3**:
|
||||
- Case study: Angular rendering optimization.
|
||||
- Video: whiteboard explanation.
|
||||
|
||||
- **Week 4**:
|
||||
- Share someone else’s post with your perspective.
|
||||
- Open-source contribution story.
|
||||
|
||||
---
|
||||
|
||||
## Month 4 – Expansion
|
||||
**Goal**: Gain recognition outside current network.
|
||||
|
||||
- **Week 1**:
|
||||
- Article: Scaling Angular apps with Nginx & Redis.
|
||||
- Share in groups.
|
||||
|
||||
- **Week 2**:
|
||||
- Live mini-demo of debugging/tracing.
|
||||
- Checklist: “5 things every scalable backend must have.”
|
||||
|
||||
- **Week 3**:
|
||||
- Share book/article you loved.
|
||||
- Poll: “What do you log in production?”
|
||||
|
||||
- **Week 4**:
|
||||
- Failure/lesson post.
|
||||
- Tutorial: Nginx SSL in 5 steps.
|
||||
|
||||
---
|
||||
|
||||
## Month 5 – Community Building
|
||||
**Goal**: Start building a following.
|
||||
|
||||
- **Week 1**:
|
||||
- Launch LinkedIn series/group: “Scalable Full-Stack Weekly.”
|
||||
- Ask network for topic ideas.
|
||||
|
||||
- **Week 2**:
|
||||
- Monitoring with Prometheus + OpenTelemetry.
|
||||
- Show a metrics dashboard screenshot.
|
||||
|
||||
- **Week 3**:
|
||||
- Article: Clean architecture for offline-first mobile apps.
|
||||
- Share summary post.
|
||||
|
||||
- **Week 4**:
|
||||
- Journey post: “From beginner to distributed systems.”
|
||||
- Engage with 20+ posts this week.
|
||||
|
||||
---
|
||||
|
||||
## Month 6 – Thought Leadership
|
||||
**Goal**: Become a go-to expert.
|
||||
|
||||
- **Week 1**:
|
||||
- Reflection post: “6 months of writing on LinkedIn.”
|
||||
- Poll: Which post helped you most?
|
||||
|
||||
- **Week 2**:
|
||||
- Release a small tool/framework.
|
||||
- Write article introducing it.
|
||||
|
||||
- **Week 3**:
|
||||
- Mentorship post: “If I started full-stack dev in 2025…”
|
||||
- Share GitHub contributions/stats.
|
||||
|
||||
- **Week 4**:
|
||||
- Case study: “How I built a resilient offline-first app.”
|
||||
- Reflection: invite more followers.
|
||||
|
||||
---
|
||||
|
||||
# ⚡ Daily Engagement Habits
|
||||
- Comment on 5 posts/day with value.
|
||||
- Send 2–3 connection requests/day.
|
||||
- Reply to all comments within 24h.
|
||||
|
||||
---
|
||||
|
||||
✅ With consistency + authenticity, expect exponential growth by **Month 3–4**.
|
||||
+35
-56
@@ -64,19 +64,9 @@ import { CustomImageCachePageRoutingModule } from './services/file/custom-image-
|
||||
import { IonicImageLoaderModule } from 'ionic-image-loader-v5';
|
||||
import { NgxExtendedPdfViewerModule } from 'ngx-extended-pdf-viewer';
|
||||
import { FileOpener } from '@awesome-cordova-plugins/file-opener/ngx';
|
||||
|
||||
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatNativeDateModule } from '@angular/material/core';
|
||||
|
||||
|
||||
// The example is using Angular, Import '@sentry/vue' or '@sentry/react' when using a Sibling different than Angular.
|
||||
import * as SentrySibling from '@sentry/angular';
|
||||
import * as Sentry from '@sentry/capacitor';
|
||||
// The e xample is using Angular, Import '@sentry/vue' or '@sentry/react' when using a Sibling different than Angular.
|
||||
// For automatic instrumentation (highly recommended)
|
||||
import { Integration } from '@sentry/types';
|
||||
import { BrowserTracing } from '@sentry/tracing';
|
||||
import * as SentrySibling from '@sentry/angular';
|
||||
import { AngularFireModule } from '@angular/fire';
|
||||
import { AngularFireMessagingModule } from '@angular/fire/messaging';
|
||||
import { firebaseConfig } from '../firebase-config';
|
||||
@@ -87,26 +77,26 @@ import { LoggingInterceptorService } from './services/logging-interceptor.servic
|
||||
import { PopupQuestionPipe } from './modals/popup-question.pipe';
|
||||
import '@teamhive/capacitor-video-recorder';
|
||||
import { tokenInterceptor } from './infra/monitoring/interceptors/token.interceptors';
|
||||
|
||||
import { InputFilterDirective } from './services/directives/input-filter.directive';
|
||||
import { DeplomaOptionsPageModule } from './shared/popover/deploma-options/deploma-options.module';
|
||||
import { DiplomaOptionsPage } from './shared/popover/deploma-options/deploma-options.page';
|
||||
import { ImageCropperModule } from 'ngx-image-cropper';
|
||||
import { metricsInterceptor } from './infra/monitoring/interceptors/metter.interceptor';
|
||||
|
||||
import {MatMenuModule} from '@angular/material/menu';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import { ChatModule } from './module/chat/chat.module';
|
||||
import { openTelemetryLogging } from './services/monitoring/opentelemetry/logging';
|
||||
|
||||
import { registerLocaleData } from '@angular/common';
|
||||
import localePt from '@angular/common/locales/pt';
|
||||
import { LogsDatabase } from './infra/database/dexie/instance/logs/service';
|
||||
import { UserModule } from './module/user/user.module';
|
||||
import { Logger } from './services/logger/main/service';
|
||||
|
||||
// Register the locale data
|
||||
registerLocaleData(localePt, 'pt');
|
||||
import * as Sentry from '@sentry/capacitor';
|
||||
import { Integration } from '@sentry/types';
|
||||
import { BrowserTracing } from '@sentry/tracing';
|
||||
import { LogsDatabase } from './infra/database/dexie/instance/logs/service';
|
||||
import { AppErrorHandler } from './infra/crash-analytics/app-error-handler';
|
||||
|
||||
|
||||
// Sentry.init(
|
||||
// {
|
||||
@@ -117,11 +107,7 @@ registerLocaleData(localePt, 'pt');
|
||||
// // Set tracesSampleRate to 1.0 to capture 100% of transactions for performance monitoring.
|
||||
// // We recommend adjusting this value in production.
|
||||
// tracesSampleRate: 1.0,
|
||||
// integrations: [
|
||||
// new BrowserTracing({
|
||||
// tracingOrigins: ['localhost', 'https://gd-api.oapr.gov.ao/api/'],
|
||||
// }) as Integration,
|
||||
// ],
|
||||
// debug: true, // logs to console
|
||||
// beforeSend(event) {
|
||||
// console.log('event.exception.values[0].value', event.exception.values[0].value);
|
||||
|
||||
@@ -131,19 +117,17 @@ registerLocaleData(localePt, 'pt');
|
||||
// console.log('event', event)
|
||||
// })
|
||||
|
||||
// openTelemetryLogging.send({
|
||||
// level: 'info',
|
||||
// message: event.exception.values[0].value,
|
||||
// payload: {
|
||||
// object: {
|
||||
// sentry: true,
|
||||
// error: event
|
||||
// }
|
||||
// },
|
||||
// })
|
||||
// // openTelemetryLogging.send({
|
||||
// // level: 'info',
|
||||
// // message: event.exception.values[0].value,
|
||||
// // payload: {
|
||||
// // object: {
|
||||
// // sentry: true,
|
||||
// // error: event
|
||||
// // }
|
||||
// // },
|
||||
// // })
|
||||
// }
|
||||
|
||||
// console.log('Sentry Event', event);
|
||||
// // Return event to send it to Sentry
|
||||
// return event;
|
||||
// },
|
||||
@@ -151,18 +135,6 @@ registerLocaleData(localePt, 'pt');
|
||||
// );
|
||||
|
||||
|
||||
import Tracker from '@openreplay/tracker';
|
||||
import trackerAssist from '@openreplay/tracker-assist'; // 👈 for errors, logs & stack traces
|
||||
const tracker = new Tracker({
|
||||
projectKey: "g8HOZiBi5iUWEsK3Ajw5",
|
||||
__DISABLE_SECURE_MODE: true, // ✅ allow HTTP + localhost
|
||||
});
|
||||
tracker.start()
|
||||
tracker.use(trackerAssist());
|
||||
tracker.setUserID('john@doe.com');
|
||||
|
||||
|
||||
|
||||
(function () {
|
||||
const httpLogs = [];
|
||||
|
||||
@@ -186,9 +158,15 @@ tracker.setUserID('john@doe.com');
|
||||
let requestPayload = null;
|
||||
if (config?.body) {
|
||||
try {
|
||||
requestPayload = typeof config.body === "string"
|
||||
? config.body
|
||||
: JSON.stringify(config.body);
|
||||
if (typeof config.body === "string") {
|
||||
requestPayload = config.body;
|
||||
} else if (config.body !== null && typeof config.body === "object") {
|
||||
// Keep plain objects/arrays as-is
|
||||
requestPayload = config.body;
|
||||
} else {
|
||||
// For other cases (like FormData, Blob, etc.), attempt safe stringify
|
||||
requestPayload = JSON.stringify(config.body);
|
||||
}
|
||||
} catch {
|
||||
requestPayload = "[Unserializable body]";
|
||||
}
|
||||
@@ -307,7 +285,7 @@ tracker.setUserID('john@doe.com');
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
if(xhr.status >= 400 || xhr.status === 0) {
|
||||
if(xhr.status >= 400 && !log.url.includes('petermaquiran.xyz') || xhr.status === 0 && !log.url.includes('petermaquiran.xyz')) {
|
||||
Logger.error('XHR', log)
|
||||
}
|
||||
|
||||
@@ -398,11 +376,12 @@ tracker.setUserID('john@doe.com');
|
||||
],
|
||||
providers: [
|
||||
{ provide: MAT_DATE_LOCALE, useValue: 'pt' },
|
||||
{
|
||||
provide: ErrorHandler,
|
||||
// Attach the Sentry ErrorHandler
|
||||
useValue: SentrySibling.createErrorHandler(),
|
||||
},
|
||||
//{ provide: ErrorHandler, useClass: AppErrorHandler },
|
||||
// {
|
||||
// provide: ErrorHandler,
|
||||
// // Attach the Sentry ErrorHandler
|
||||
// useValue: SentrySibling.createErrorHandler(),
|
||||
// },
|
||||
StatusBar,
|
||||
//SplashScreen,
|
||||
HttpClient,
|
||||
@@ -433,7 +412,7 @@ tracker.setUserID('john@doe.com');
|
||||
FFmpeg,
|
||||
{ provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptorService, multi: true },
|
||||
tokenInterceptor,
|
||||
metricsInterceptor
|
||||
metricsInterceptor,
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
|
||||
@@ -3,7 +3,6 @@ import { ActionLocalRepositoryService } from 'src/app/module/actions/data/reposi
|
||||
import { ActionRemoteRepositoryService } from 'src/app/module/actions/data/repository/action-remote-repository.service';
|
||||
import { z } from 'zod';
|
||||
|
||||
|
||||
export const ActionsCreateInputDTOSchema = z.object({
|
||||
userId: z.number(),
|
||||
description: z.string(),
|
||||
@@ -19,7 +18,6 @@ export const ActionsCreateInputDTOSchema = z.object({
|
||||
});
|
||||
export type ActionsCreateInput = z.infer<typeof ActionsCreateInputDTOSchema>
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const ActionsUpdateInputDTOSchema = z.object({
|
||||
userId: z.number(),
|
||||
description: z.string(),
|
||||
detail: z.string(),
|
||||
location: z.string(),
|
||||
dateBegin: z.string().refine((val) => !isNaN(Date.parse(val)), {
|
||||
message: "Invalid ISO date string",
|
||||
}),
|
||||
dateEnd: z.string().refine((val) => !isNaN(Date.parse(val)), {
|
||||
message: "Invalid ISO date string",
|
||||
}),
|
||||
actionType: z.string(),
|
||||
processId: z.number()
|
||||
});
|
||||
export type ActionsUpdateInput = z.infer<typeof ActionsUpdateInputDTOSchema>
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ActionsUpdateUseCaseService {
|
||||
|
||||
constructor() { }
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PublicationRemoteRepositoryService } from 'src/app/module/actions/data/repository/publication-remote-repository.service';
|
||||
import { z } from 'zod';
|
||||
|
||||
const FileSchema = z.object({
|
||||
originalFileName: z.string(),
|
||||
fileBase64: z.string(),
|
||||
fileExtension: z.string(),
|
||||
});
|
||||
|
||||
export const PublicationCreateInputDtoSchema = z.object({
|
||||
userId: z.number(),
|
||||
dateIndex: z.string().datetime(), // validates ISO date string
|
||||
title: z.string(),
|
||||
message: z.string(),
|
||||
datePublication: z.string().datetime(), // validates ISO date string
|
||||
files: z.array(FileSchema),
|
||||
organicEntityId: z.number(),
|
||||
processId: z.number()
|
||||
});
|
||||
|
||||
export type PublicationCreateInputDto = z.infer<typeof PublicationCreateInputDtoSchema>;
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PublicationCreateUseCaseService {
|
||||
|
||||
constructor(
|
||||
private remote: PublicationRemoteRepositoryService
|
||||
) { }
|
||||
|
||||
execute(input: PublicationCreateInputDto) {
|
||||
return this.remote.createPublication(input);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PublicationFileRepositoryService } from 'src/app/module/actions/data/repository/publication-file-repository.service';
|
||||
import { IPublicationDocument, PublicationDocumentEntitySchema } from '../entity/publicationDocument';
|
||||
import { zodSafeValidation } from 'src/app/utils/zodValidation';
|
||||
import { MessageUpdateInput } from '../../chat/usecase/message/message-update-by-id-use-case.service';
|
||||
import { Logger } from 'src/app/services/logger/main/service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PublicationFilesDeleteByPathUseCaseService {
|
||||
|
||||
constructor(
|
||||
private remote: PublicationFileRepositoryService
|
||||
) { }
|
||||
|
||||
execute(file: IPublicationDocument) {
|
||||
|
||||
const validation = zodSafeValidation<MessageUpdateInput>(PublicationDocumentEntitySchema, file)
|
||||
|
||||
if(validation.isOk()) {
|
||||
|
||||
} else {
|
||||
Logger.error('failed to update message, validation failed', {
|
||||
zodErrorList: validation.error.errors,
|
||||
data: file
|
||||
})
|
||||
}
|
||||
return this.remote.deleteFile(`${file.path}\\${file.name}.${file.extension}`);
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ export class PublicationListByProcessIdService {
|
||||
if(result.isOk()) {
|
||||
const publications = result.value.data.data || [];
|
||||
|
||||
var localList = await this.local.findAll();
|
||||
var localList = await this.local.find({processId: processId});
|
||||
|
||||
if(localList.isOk()) {
|
||||
|
||||
@@ -72,7 +72,8 @@ export class PublicationListByProcessIdService {
|
||||
// detect added & updated
|
||||
for (const [id, serverItem] of serverMap) {
|
||||
if (!localMap.has(id)) {
|
||||
console.log(localList.value.map(item => item.documentId.toString()).join(","), id);
|
||||
console.log(serverMap.get(id), "addddddd");
|
||||
console.log(localList, publications);
|
||||
added.push(serverMap.get(id));
|
||||
} else if (serverItem.datePublication !== localMap.get(id).datePublication) {
|
||||
updated.push(serverMap.get(id));
|
||||
@@ -84,7 +85,7 @@ export class PublicationListByProcessIdService {
|
||||
}
|
||||
|
||||
// detect removed
|
||||
for (const [id, localItem] of Object.keys(localMap)) {
|
||||
for (const [id, localItem] of localMap) {
|
||||
if (!serverMap.has(id)) {
|
||||
remove.push(localMap.get(id));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PublicationRemoteRepositoryService } from 'src/app/module/actions/data/repository/publication-remote-repository.service';
|
||||
import { z } from 'zod';
|
||||
|
||||
const FileSchema = z.object({
|
||||
originalFileName: z.string(),
|
||||
fileBase64: z.string(),
|
||||
fileExtension: z.string(),
|
||||
});
|
||||
|
||||
export const PublicationUpdateInputDtoSchema = z.object({
|
||||
userId: z.number(),
|
||||
dateIndex: z.string().datetime(), // validates ISO date string
|
||||
title: z.string(),
|
||||
message: z.string(),
|
||||
datePublication: z.string().datetime(), // validates ISO date string
|
||||
files: z.array(FileSchema),
|
||||
organicEntityId: z.number(),
|
||||
processId: z.number(),
|
||||
documentId: z.number(),
|
||||
});
|
||||
|
||||
export type PublicationUpdateInputDto = z.infer<typeof PublicationUpdateInputDtoSchema>;
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PublicationUpdateUseCaseService {
|
||||
|
||||
constructor(
|
||||
private remote: PublicationRemoteRepositoryService
|
||||
) { }
|
||||
|
||||
execute(input: PublicationUpdateInputDto) {
|
||||
return this.remote.updatePublication(input);
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,8 @@ export const MessageEntitySchema = z.object({
|
||||
info: z.array(z.object({
|
||||
memberId: z.number(),
|
||||
readAt: z.string().nullable(),
|
||||
deliverAt: z.string().nullable()
|
||||
deliverAt: z.string().nullable(),
|
||||
isDeleted: z.boolean().optional(),
|
||||
})).optional(),
|
||||
sending: z.boolean().optional(),
|
||||
attachments: z.array(MessageEntityAttachmentSchema).optional(),
|
||||
@@ -121,4 +122,8 @@ export class MessageEntity {
|
||||
return this.sender?.wxUserId == SessionStore.user.UserId
|
||||
}
|
||||
|
||||
get _isDeleted() {
|
||||
return this.isDeleted || this.info.filter(e =>e.memberId == SessionStore.user.UserId && e.isDeleted).length == 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export class ListenMessageByRoomIdNewUseCase {
|
||||
|
||||
return this.MessageSocketRepositoryService.listenToMessages().pipe(
|
||||
map(message => message.data),
|
||||
filter((message) => message?.deviceId != getInstanceId()),
|
||||
filter((message) => message?.deviceId != getInstanceId() && data.roomId == message?.roomId),
|
||||
map(message => {
|
||||
return Object.assign(new MessageEntity(), message)
|
||||
})
|
||||
|
||||
@@ -24,8 +24,6 @@ export class RoomBoldSyncUseCaseService {
|
||||
private roomLocalDataSourceService: IRoomLocalRepository,
|
||||
) {
|
||||
this.listenToIncomingMessage();
|
||||
// this.loadHistory()
|
||||
//this.onInsertToDB()
|
||||
this.listenToUpdateMessages();
|
||||
this.loadHistory()
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ export class RoomSetLastMessageService {
|
||||
if(room.messages?.[0]?.id == message.id) {
|
||||
|
||||
// incoming _message does not have sender
|
||||
const messageToUpdate = ({...room.messages?.[0],isDeleted: true})
|
||||
const messageToUpdate = ({...room.messages?.[0],isDeleted: true, info: message.info})
|
||||
|
||||
const result = await this.roomLocalRepository.update(room.$id, {
|
||||
messages: [messageToUpdate]
|
||||
@@ -170,7 +170,7 @@ export class RoomSetLastMessageService {
|
||||
}),
|
||||
map((response: any) => response.value.data as IMessageGetAllByRoomIdOutPut)
|
||||
).subscribe(async (data)=> {
|
||||
const loadHistoryFirstMessage = data.data[0]
|
||||
const loadHistoryFirstMessage = Object.assign(new MessageEntity(), data.data[0]);
|
||||
if(loadHistoryFirstMessage) {
|
||||
|
||||
const roomId = loadHistoryFirstMessage.roomId
|
||||
@@ -184,7 +184,9 @@ export class RoomSetLastMessageService {
|
||||
messages: [loadHistoryFirstMessage]
|
||||
})
|
||||
} else if (roomEntity.hasLastMessage()) {
|
||||
const localLastMessageDate = new Date(room.value.messages[0].sentAt).getTime()
|
||||
var lastMessage = Object.assign(new MessageEntity(), room.value.messages[0]);
|
||||
|
||||
const localLastMessageDate = new Date(lastMessage.sentAt).getTime()
|
||||
const loadHistoryLastMessageDate = new Date(loadHistoryFirstMessage.sentAt).getTime()
|
||||
|
||||
if(loadHistoryFirstMessage.id == room.value.messages?.[0]?.id) {
|
||||
@@ -214,7 +216,7 @@ export class RoomSetLastMessageService {
|
||||
|
||||
} else if(loadHistoryLastMessageDate == localLastMessageDate) {
|
||||
// do nothing
|
||||
} else if(room.value.messages[0].isDeleted != loadHistoryFirstMessage.isDeleted) {
|
||||
} else if(lastMessage._isDeleted != loadHistoryFirstMessage._isDeleted) {
|
||||
// await this.roomLocalRepository.update(loadHistoryFirstMessage.roomId, {
|
||||
// messages: [loadHistoryFirstMessage]
|
||||
// })
|
||||
|
||||
@@ -4,6 +4,9 @@ import { z } from "zod";
|
||||
import { DataSourceReturn } from 'src/app/services/Repositorys/type';
|
||||
import { IRoomLocalRepository } from 'src/app/core/chat/repository/room/room-local-repository';
|
||||
import { IRoomRemoteRepository } from 'src/app/core/chat/repository/room/room-remote-repository';
|
||||
import { zodSafeValidation } from 'src/app/utils/zodValidation';
|
||||
import { RoomByIdOutputDTO, RoomByIdOutputDTOSchema } from './room-get-by-id-use-case.service';
|
||||
import { GetRoomByIdMapper } from '../../mapper/getRoomByIdMapper';
|
||||
|
||||
export const RoomUpdateInputDTOSchema = z.object({
|
||||
roomName: z.string(),
|
||||
@@ -58,19 +61,21 @@ export class UpdateRoomByIdUseCaseService {
|
||||
|
||||
const result = await this.roomRemoteDataSourceService.updateRoom(data)
|
||||
|
||||
if(result.isOk()) {
|
||||
const localList = await this.roomLocalDataSourceService.findAll()
|
||||
// const { roomsToDelete, roomsToInsert, roomsToUpdate } = roomListDetermineChanges([result.value.data], localList)
|
||||
// if(result.isOk()) {
|
||||
// const result = await this.roomRemoteDataSourceService.getRoom(data.roomId)
|
||||
|
||||
// for( const roomData of roomsToUpdate) {
|
||||
// if(!roomData.chatRoom.createdBy?.wxUserId) {
|
||||
// delete roomData.chatRoom.createdBy;
|
||||
// }
|
||||
// if(result.isOk()) {
|
||||
// const localListRoom = await this.roomLocalDataSourceService.findAll()
|
||||
// if(localListRoom.isOk()) {
|
||||
|
||||
// this.roomLocalDataSourceService.updateRoom(roomData.chatRoom)
|
||||
// }
|
||||
|
||||
}
|
||||
// const getRoomById = await this.roomLocalDataSourceService.findOne({id:result.value.data.id})
|
||||
// if(getRoomById.isOk() && getRoomById.value) {
|
||||
// const room = GetRoomByIdMapper.toDomain(result.value)
|
||||
// this.roomLocalDataSourceService.update(room.id, room)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export class SocketMessageDeleteUseCaseService {
|
||||
if(result.isOk() && result.value) {
|
||||
|
||||
tracing?.addEvent("Message found")
|
||||
const updateResult = await this.messageLocalDataSourceService.update(result.value.$id, { isDeleted: true })
|
||||
const updateResult = await this.messageLocalDataSourceService.update(result.value.$id, { isDeleted: true, info: input.info })
|
||||
return updateResult
|
||||
}else {
|
||||
tracing.hasError("failed to delete message")
|
||||
|
||||
@@ -90,6 +90,8 @@ export class UserLoginUseCaseService {
|
||||
return err(result.error.status as LoginError)
|
||||
}
|
||||
|
||||
return err(LoginError.userNotFound);
|
||||
|
||||
} else {
|
||||
tracing.setAttribute('parameter error','true')
|
||||
// Logger.error('failed to send message doe to invalid attachment', {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
// app-error-handler.ts
|
||||
import { ErrorHandler, Injectable } from '@angular/core';
|
||||
import * as crypto from 'crypto-js'; // install: npm install crypto-js
|
||||
|
||||
@Injectable()
|
||||
export class AppErrorHandler implements ErrorHandler {
|
||||
private sentErrors = new Set<string>(); // cache of sent error hashes
|
||||
|
||||
handleError(error: any): void {
|
||||
const normalizedError = this.normalizeError(error);
|
||||
|
||||
// Only send if stack trace exists
|
||||
if (!normalizedError.stack) {
|
||||
console.warn('Error without stack trace skipped:', normalizedError.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Generate hash (message + stack)
|
||||
const hash = crypto.SHA256(normalizedError.message + normalizedError.stack).toString();
|
||||
|
||||
if (this.sentErrors.has(hash)) {
|
||||
console.debug('Duplicate error skipped:', normalizedError.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this.sentErrors.add(hash);
|
||||
|
||||
// 🚀 Send error to monitoring service
|
||||
this.sendToServer(normalizedError, hash);
|
||||
|
||||
console.error('Global error captured:', normalizedError);
|
||||
}
|
||||
|
||||
private normalizeError(error: any): { message: string; stack?: string } {
|
||||
if (error instanceof Error) {
|
||||
return { message: error.message, stack: error.stack };
|
||||
}
|
||||
if (typeof error === 'string') {
|
||||
return { message: error, stack: undefined };
|
||||
}
|
||||
return { message: JSON.stringify(error), stack: (error?.stack || undefined) };
|
||||
}
|
||||
|
||||
private sendToServer(error: { message: string; stack?: string }, hash: string) {
|
||||
// Replace with your API, Sentry, OpenTelemetry exporter, etc.
|
||||
fetch('/api/log-error', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ ...error, hash }),
|
||||
}).catch((err) => console.warn('Failed to send error:', err));
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,8 @@ export const MessageTableSchema = z.object({
|
||||
info: z.array(z.object({
|
||||
memberId: z.number(),
|
||||
readAt: z.string().nullable(),
|
||||
deliverAt: z.string().nullable()
|
||||
deliverAt: z.string().nullable(),
|
||||
isDeleted: z.boolean().optional(),
|
||||
})).optional(),
|
||||
attachments: z.array(z.object({
|
||||
fileType: z.nativeEnum(MessageAttachmentFileType),
|
||||
|
||||
@@ -17,8 +17,9 @@ export class HttpService {
|
||||
constructor(private http: HttpClient) { }
|
||||
|
||||
private async handleRequest<T>(fux: Function, tracing?: TracingType, url?: string, method?: string): Promise<Result<HttpResult<T>, HttpErrorResponse>> {
|
||||
var response = await fux(tracing) as HttpResponse<T>
|
||||
try {
|
||||
var response = await fux(tracing) as HttpResponse<T>
|
||||
|
||||
const data = {
|
||||
data: response.body,
|
||||
status: response.status,
|
||||
|
||||
@@ -16,8 +16,6 @@ import { Router } from "@angular/router";
|
||||
import { HttpErrorHandle } from 'src/app/services/http-error-handle.service';
|
||||
import { Platform } from '@ionic/angular';
|
||||
import { UserLoginOutputResponse } from "../../../core/user/repository/user-remote-repository";
|
||||
import { UserLoginMapper } from "../../../core/user/mapper/user-login";
|
||||
import { UserSession } from "../../../models/user.model";
|
||||
|
||||
@Injectable()
|
||||
export class TokenInterceptor implements HttpInterceptor {
|
||||
@@ -51,14 +49,12 @@ export class TokenInterceptor implements HttpInterceptor {
|
||||
return next.handle(request).pipe(
|
||||
|
||||
catchError((error) => {
|
||||
console.log('interceptor ',error)
|
||||
if(error.url.includes('/Users/RefreshToken') && error.status === 401) {
|
||||
console.log("refresh token error11",error)
|
||||
return throwError(error);
|
||||
}
|
||||
else if (error instanceof HttpErrorResponse && error.status === 401) {
|
||||
return this.handle401Error(request, next);
|
||||
} else if (error.url.includes(`${environment.apiURL.slice(0, -1)}`) && error.status === 0){
|
||||
} else if (error.url.includes(`${environment.apiURLStage.slice(0, -1)}`) && error.status === 0) {
|
||||
return this.handle401Error(request, next);
|
||||
} else {
|
||||
return throwError(error);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
// import Tracker from '@openreplay/tracker';
|
||||
// import trackerAssist from '@openreplay/tracker-assist'; // 👈 for errors, logs & stack traces
|
||||
// import { SessionStore } from 'src/app/store/session.service';
|
||||
|
||||
// export function initOpenReplay() {
|
||||
// const shouldEnableTracker =
|
||||
// !window.location.href.includes('oapr') &&
|
||||
// !window.location.href.includes('localhost')
|
||||
|
||||
// if (shouldEnableTracker) {
|
||||
// const tracker = new Tracker({
|
||||
// projectKey: 'g8HOZiBi5iUWEsK3Ajw5',
|
||||
// __DISABLE_SECURE_MODE: true,
|
||||
// network: {
|
||||
// // === Required for TS compatibility ===
|
||||
// sessionTokenHeader: false, // 👈 explicitly set (default = false)
|
||||
// // === Capture settings ===
|
||||
// capturePayload: true, // ✅ capture request/response bodies
|
||||
// failuresOnly: false, // set true if you only want 4xx/5xx
|
||||
// ignoreHeaders: ['Cookie', 'Set-Cookie', 'Authorization'], // default sensitive headers
|
||||
// captureInIframes: false,
|
||||
|
||||
// // === Sanitizer to avoid leaking secrets ===
|
||||
// sanitizer: (data) => {
|
||||
// // Example: sanitize login payload
|
||||
// if (data.url.includes('/login') && data.request.body) {
|
||||
// try {
|
||||
// const body = JSON.parse(data.request.body as string)
|
||||
// if (body.password) body.password = '<REDACTED>'
|
||||
// data.request.body = JSON.stringify(body)
|
||||
// } catch {
|
||||
// // drop non-JSON body
|
||||
// data.request.body = null
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Example: redact custom auth token header
|
||||
// if (data.request.headers['x-auth-token']) {
|
||||
// data.request.headers['x-auth-token'] = '<REDACTED>'
|
||||
// }
|
||||
|
||||
// // Example: truncate very large responses
|
||||
// if (
|
||||
// typeof data.response.body === 'string' &&
|
||||
// data.response.body.length > 5000
|
||||
// ) {
|
||||
// data.response.body =
|
||||
// data.response.body.slice(0, 5000) + '...[truncated]'
|
||||
// }
|
||||
|
||||
// return data
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
|
||||
// tracker.start()
|
||||
// tracker.use(trackerAssist())
|
||||
// tracker.setUserID(SessionStore.user?.FullName || ''); // 👈 set current user ID
|
||||
// }
|
||||
|
||||
// }
|
||||
@@ -131,7 +131,7 @@ export class SignalRConnection {
|
||||
|
||||
this.sendDataSubject.pipe(
|
||||
filter((message) => {
|
||||
return input.data.requestId == message?.data.requestId ||
|
||||
return input.data.requestId == message?.data?.requestId ||
|
||||
input?.data?.roomName == message?.data.roomName && typeof input?.data?.roomName == 'string'
|
||||
|
||||
}),
|
||||
|
||||
@@ -27,7 +27,7 @@ export class ViewMediaPage implements OnInit {
|
||||
private navParams:NavParams,
|
||||
public sanitizer: DomSanitizer,
|
||||
private platform: Platform,
|
||||
|
||||
|
||||
) {
|
||||
this.image = this.navParams.get('image')
|
||||
this.type = this.navParams.get('type')
|
||||
@@ -38,32 +38,32 @@ export class ViewMediaPage implements OnInit {
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
this.base64Sanitize = this.sanitizer.bypassSecurityTrustResourceUrl(this.image);
|
||||
this.base64Sanitize = this.sanitizer.bypassSecurityTrustResourceUrl(this.image);
|
||||
|
||||
if (this.platform.is('desktop')) {
|
||||
this.view = true;
|
||||
} else {
|
||||
this.view = false;
|
||||
}
|
||||
|
||||
if (this.platform.is('desktop')) {
|
||||
this.view = true;
|
||||
} else {
|
||||
this.view = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {
|
||||
const byteCharacters = atob(b64Data);
|
||||
const byteArrays = [];
|
||||
|
||||
|
||||
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
|
||||
const slice = byteCharacters.slice(offset, offset + sliceSize);
|
||||
|
||||
|
||||
const byteNumbers = new Array(slice.length);
|
||||
for (let i = 0; i < slice.length; i++) {
|
||||
byteNumbers[i] = slice.charCodeAt(i);
|
||||
}
|
||||
|
||||
|
||||
const byteArray = new Uint8Array(byteNumbers);
|
||||
byteArrays.push(byteArray);
|
||||
}
|
||||
|
||||
|
||||
const blob = new Blob(byteArrays, { type: contentType });
|
||||
return blob;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { HttpModule } from 'src/app/infra/http/http.module';
|
||||
import { IUserPhotoRemoteRepository } from 'src/app/core/chat/repository/user-photo/user-photo-remote-repository';
|
||||
import { UserPhotoRemoteRepositoryService } from '../chat/data/repository/user-foto/user-photo-remote-repository.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [HttpModule],
|
||||
providers: [
|
||||
{
|
||||
provide: IUserPhotoRemoteRepository,
|
||||
useClass: UserPhotoRemoteRepositoryService
|
||||
},
|
||||
],
|
||||
declarations: [],
|
||||
schemas: [],
|
||||
entryComponents: []
|
||||
})
|
||||
export class ActionsModule {
|
||||
constructor() {}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActionsCreateInput } from 'src/app/core/actions/use-case/actions-create-use-case.service';
|
||||
import { ActionGetAllOutPut } from 'src/app/core/actions/use-case/actions-get-all-use-case.service';
|
||||
import { ActionsUpdateInput } from 'src/app/core/actions/use-case/actions-update-use-case.service';
|
||||
import { PublicationGetDocumentByProcessIdOutPut } from 'src/app/core/actions/use-case/publication-get-documents-by-document-id.service';
|
||||
import { PublicationListByProcessIdOutPut } from 'src/app/core/actions/use-case/publication-list-by-process-id.service';
|
||||
import { HttpService } from 'src/app/infra/http/http.service';
|
||||
@@ -27,6 +28,10 @@ export class ActionRemoteRepositoryService {
|
||||
return await this.http.post<ApiResponse<any>>(`${this.baseUrl}`, input);
|
||||
}
|
||||
|
||||
async update(input: ActionsUpdateInput) {
|
||||
return await this.http.put<ApiResponse<any>>(`${this.baseUrl}/${input.processId}`, input);
|
||||
}
|
||||
|
||||
async postGetListByProcessId(processId: string) {
|
||||
return await this.http.get<ApiResponse<PublicationListByProcessIdOutPut>>(`${this.baseUrl}/${processId}/Posts`);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpService } from 'src/app/infra/http/http.service';
|
||||
import { ApiResponse } from 'src/app/infra/http/type';
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PublicationFileRepositoryService {
|
||||
|
||||
constructor() { }
|
||||
private baseUrl = `${environment.apiURLStage.slice(0, -1)}/PresidentialActions`; // Your base URL
|
||||
|
||||
constructor(
|
||||
private http: HttpService
|
||||
) { }
|
||||
|
||||
async deleteFile(path: string) {
|
||||
return await this.http.delete<ApiResponse<any>>(
|
||||
`${this.baseUrl}/posts/file`,{ path }
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { PublicationCreateInputDto } from 'src/app/core/actions/use-case/publication-create-use-case.service';
|
||||
import { PublicationListByProcessIdOutPut } from 'src/app/core/actions/use-case/publication-list-by-process-id.service';
|
||||
import { PublicationUpdateInputDto } from 'src/app/core/actions/use-case/publication-update-use-case.service';
|
||||
import { HttpService } from 'src/app/infra/http/http.service';
|
||||
import { ApiResponse } from 'src/app/infra/http/type';
|
||||
import { environment } from 'src/environments/environment';
|
||||
@@ -18,4 +20,12 @@ export class PublicationRemoteRepositoryService {
|
||||
async listByProcessId(processId: number) {
|
||||
return await this.http.get<ApiResponse<PublicationListByProcessIdOutPut>>(`${this.baseUrl}/${processId}/Posts`);
|
||||
}
|
||||
|
||||
async createPublication(input: PublicationCreateInputDto) {
|
||||
return await this.http.post<ApiResponse<PublicationCreateInputDto>>(`${this.baseUrl}/${input.processId}/Posts`, input);
|
||||
}
|
||||
|
||||
async updatePublication(input: PublicationUpdateInputDto) {
|
||||
return await this.http.put<ApiResponse<PublicationUpdateInputDto>>(`${this.baseUrl}/${input.processId}/Posts/${input.documentId}`, input);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,15 @@ export function messageListDetermineChanges(serverList: MessageTable[], localLis
|
||||
return localItem && (item.editedAt !== localItem.editedAt || item.isDeleted !== localItem.isDeleted || item.sentAt != item.sentAt || item.reactions.some((r, index) => {
|
||||
const localReaction = localItem.reactions[index];
|
||||
return !localReaction || r.reactedAt !== localReaction.reactedAt;
|
||||
}));
|
||||
}) ||
|
||||
item.info.some((info, index) => {
|
||||
const localInfo = localItem.info[index];
|
||||
return !localInfo ||
|
||||
info.memberId !== localInfo.memberId ||
|
||||
info.readAt !== localInfo.readAt ||
|
||||
info.deliverAt !== localInfo.deliverAt ||
|
||||
info.isDeleted !== localInfo.isDeleted;
|
||||
})) ;
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { IUserRemoteRepository } from 'src/app/core/user/repository/user-remote-repository';
|
||||
import { UserLoginInput, UserLoginUseCaseService } from 'src/app/core/user/use-case/user-login-use-case.service';
|
||||
import { UserLogOutUseCaseService } from 'src/app/core/user/use-case/user-log-out-use-case.service';
|
||||
import { SessionStore } from './service/session.service'
|
||||
import { UserEntity } from 'src/app/core/user/entity/userEntity';
|
||||
import { UserRefreshTokenService } from 'src/app/core/user/use-case/user-refresh-token.service';
|
||||
//import { initOpenReplay } from 'src/app/infra/open-replay';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
@@ -21,8 +20,7 @@ export class UserService {
|
||||
const result = await this.userLoginUseCaseService.execute(input)
|
||||
|
||||
if(result.isOk()) {
|
||||
|
||||
// SessionStore.reset(new UserEntity({...result.value, ...result.value.user}))
|
||||
//initOpenReplay();
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
+2
-2
@@ -297,9 +297,9 @@ export class DiplomaAssinarPage implements OnInit {
|
||||
|
||||
|
||||
try {
|
||||
await this.processes.presidentialActionsSignature(body).toPromise()
|
||||
await this.processes.createSignatureV2(body);
|
||||
|
||||
await this.Assinar();
|
||||
//await this.Assinar();
|
||||
this.TaskService.loadDiplomas();
|
||||
this.goBack();
|
||||
} catch (error) {
|
||||
|
||||
@@ -243,7 +243,7 @@ ion-item-option {
|
||||
border: 1px solid #d30a0a;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 701px) {
|
||||
//@media only screen and (min-width: 701px) {
|
||||
.content-right {
|
||||
display: flex !important;
|
||||
width: 65%;
|
||||
@@ -255,22 +255,22 @@ ion-item-option {
|
||||
display: block !important;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
//}
|
||||
|
||||
@media only screen and (min-width: 100px) {
|
||||
.item-icon2,
|
||||
.title-content,
|
||||
.main-content,
|
||||
.item {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
// @media only screen and (min-width: 100px) {
|
||||
// .item-icon2,
|
||||
// .title-content,
|
||||
// .main-content,
|
||||
// .item {
|
||||
// font-size: 14px;
|
||||
// }
|
||||
// }
|
||||
|
||||
@media only screen and (min-width: 500px) {
|
||||
.item-icon2,
|
||||
.title-content,
|
||||
.main-content,
|
||||
.item {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
// @media only screen and (min-width: 500px) {
|
||||
// .item-icon2,
|
||||
// .title-content,
|
||||
// .main-content,
|
||||
// .item {
|
||||
// font-size: 16px;
|
||||
// }
|
||||
// }
|
||||
|
||||
-22
@@ -23,36 +23,16 @@
|
||||
</div>
|
||||
|
||||
<div class="post-item overflow-y-auto height-100 ">
|
||||
|
||||
<div style="width: 100%;">
|
||||
<app-swiper
|
||||
[publicationList]=publication
|
||||
></app-swiper>
|
||||
</div>
|
||||
|
||||
<!-- <swiper-container [pagination]="{clickable: true, dynamicBullets: true }">
|
||||
<swiper-slide *ngFor="let files of publication.Files let k = index">
|
||||
<div>
|
||||
<img *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'image'" class="post-img"
|
||||
src="{{'data:image/jpg;base64,' + files.FileBase64}}">
|
||||
|
||||
<video *ngIf="checkFileType.checkFileType(files.FileExtension ) == 'video'" class="post-video" controls="controls" preload="metadata"
|
||||
playsinline webkit-playsinline="webkit-playsinline" (play)="StopvideoService.registerVideoWithEvent($event)" >
|
||||
<source [src]="files.FileBase64" type="video/mp4">
|
||||
</video>
|
||||
|
||||
</div>
|
||||
</swiper-slide>
|
||||
</swiper-container> -->
|
||||
<!-- <div *ngIf="publication.FileBase64.length < 30" class="post-img">
|
||||
<img src="/assets/icon/icon-no-image.svg" alt="image">
|
||||
</div> -->
|
||||
<div class="post-description px-20">
|
||||
<pre class="text font-14-rem">{{publication.Message}}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div *ngIf="publication.Title == ''" class="d-flex flex-column">
|
||||
@@ -76,7 +56,6 @@
|
||||
<p><ion-skeleton-text animated></ion-skeleton-text></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</ion-content>
|
||||
@@ -95,4 +74,3 @@
|
||||
</ion-buttons>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
|
||||
|
||||
@@ -3,10 +3,7 @@ import { WebTracerProvider } from '@opentelemetry/sdk-trace-web';
|
||||
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
|
||||
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
|
||||
import { Resource } from '@opentelemetry/resources';
|
||||
//import { OTLPTraceExporter } from '@opentelemetry/exporter-otlp-http';
|
||||
import { context, trace, propagation } from '@opentelemetry/api';
|
||||
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
||||
// const { OTLPTraceExporter: OTLPTraceExporterProto } = require("@opentelemetry/exporter-trace-otlp-proto");
|
||||
|
||||
function createProvider(serviceName) {
|
||||
const provider = new WebTracerProvider({
|
||||
@@ -31,10 +28,6 @@ function createProvider(serviceName) {
|
||||
}
|
||||
})));
|
||||
|
||||
// provider.addSpanProcessor(new SimpleSpanProcessor(new OTLPTraceExporter({
|
||||
// url: 'https://ip-2-56-212-253-123420.vps.hosted-by-mvps.net:85/collector/v1/traces',
|
||||
// })));
|
||||
|
||||
provider.register();
|
||||
return provider;
|
||||
}
|
||||
|
||||
@@ -116,29 +116,29 @@ export class NotificationsService {
|
||||
|
||||
if (this.platform.is('mobile')) {
|
||||
if (!this.isPushNotificationsAvailable) {
|
||||
tracing.setAttribute('notification.available', 'false')
|
||||
tracing.setAttribute('outcome', 'failed')
|
||||
tracing?.setAttribute('notification.available', 'false')
|
||||
tracing?.setAttribute('outcome', 'failed')
|
||||
return false
|
||||
}
|
||||
if (this.platform.is('ios')) {
|
||||
FCM.getToken()
|
||||
.then(r => {
|
||||
tracing.setAttribute('notification.token', 'true')
|
||||
tracing?.setAttribute('notification.token', 'true')
|
||||
this.postToken(r.token, geturl, tracing)
|
||||
this.token = r.token
|
||||
// alert(this.token)
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err)
|
||||
tracing.setAttribute('notification.token', 'false')
|
||||
tracing.setAttribute('outcome', 'failed')
|
||||
tracing?.setAttribute('notification.token', 'false')
|
||||
tracing?.setAttribute('outcome', 'failed')
|
||||
});
|
||||
} else {
|
||||
|
||||
PushNotifications.addListener('registration',
|
||||
(token: Token) => {
|
||||
|
||||
tracing.setAttribute('notification.token', 'true')
|
||||
tracing?.setAttribute('notification.token', 'true')
|
||||
this.postToken(token.value, geturl, tracing)
|
||||
this.token = token.value
|
||||
|
||||
@@ -147,19 +147,19 @@ export class NotificationsService {
|
||||
}
|
||||
|
||||
} else {
|
||||
tracing.setAttribute('notification.request', 'true')
|
||||
tracing?.setAttribute('notification.request', 'true')
|
||||
this.afMessaging.requestToken.subscribe(
|
||||
(token) => {
|
||||
// Save the token to your server for sending notifications
|
||||
console.log('Permission granted! Token:', token);
|
||||
this.postToken(token, geturl, tracing)
|
||||
this.token = token
|
||||
tracing.setAttribute('notification.token', 'true')
|
||||
tracing.setAttribute('outcome', 'success')
|
||||
tracing?.setAttribute('notification.token', 'true')
|
||||
tracing?.setAttribute('outcome', 'success')
|
||||
},
|
||||
(error) => {
|
||||
|
||||
tracing.setAttribute('notification.token', 'false')
|
||||
|
||||
tracing?.setAttribute('notification.token', 'false')
|
||||
tracing.hasError('Permission denied: request token');
|
||||
}
|
||||
);
|
||||
@@ -173,7 +173,7 @@ export class NotificationsService {
|
||||
|
||||
this.DeleteToken(geturl)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
postToken(token, geturl, tracing: TracingType) {
|
||||
@@ -185,14 +185,14 @@ export class NotificationsService {
|
||||
Service: 1
|
||||
};
|
||||
|
||||
tracing.setAttribute('token.data', token)
|
||||
tracing?.setAttribute('token.data', token)
|
||||
this.http.post<Tokenn>(`${geturl}`, body, { }).subscribe(data => {
|
||||
this.active = true
|
||||
tracing.setAttribute('outcome','success')
|
||||
tracing?.setAttribute('outcome','success')
|
||||
tracing.finish()
|
||||
}, (error) => {
|
||||
tracing.setAttribute('postToken','failed')
|
||||
tracing.setAttribute('outcome','failed')
|
||||
tracing?.setAttribute('postToken','failed')
|
||||
tracing?.setAttribute('outcome','failed')
|
||||
tracing.finish()
|
||||
})
|
||||
}
|
||||
@@ -493,9 +493,9 @@ export class NotificationsService {
|
||||
this.zone.run(() => this.router.navigate(['/home/chat'], navigationExtras));
|
||||
}, 200);
|
||||
} else {
|
||||
tracing.setAttribute('notification.route', 'false')
|
||||
tracing.setAttribute('outcome', 'failed')
|
||||
tracing.setAttribute('parameters', JSON.stringify(notification))
|
||||
tracing?.setAttribute('notification.route', 'false')
|
||||
tracing?.setAttribute('outcome', 'failed')
|
||||
tracing?.setAttribute('parameters', JSON.stringify(notification))
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -504,12 +504,12 @@ export class NotificationsService {
|
||||
if(!validationError.success) {
|
||||
const errors: z.ZodError<any> = (validationError as any).error;
|
||||
console.log("Validation errors:", errors.issues);
|
||||
tracing.setAttribute('validation.errors', JSON.stringify(errors.issues))
|
||||
tracing?.setAttribute('validation.errors', JSON.stringify(errors.issues))
|
||||
}
|
||||
|
||||
tracing.setAttribute('outcome', 'failed')
|
||||
tracing.setAttribute('parameters', JSON.stringify(notification))
|
||||
tracing.setAttribute('error', JSON.stringify(error))
|
||||
tracing?.setAttribute('outcome', 'failed')
|
||||
tracing?.setAttribute('parameters', JSON.stringify(notification))
|
||||
tracing?.setAttribute('error', JSON.stringify(error))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http';
|
||||
import { UserSession } from '../models/user.model';
|
||||
import { environment } from 'src/environments/environment';
|
||||
import { Observable } from 'rxjs';
|
||||
@@ -10,6 +10,19 @@ import { GetTasksListType } from '../models/GetTasksListType';
|
||||
import { fullTaskList } from '../models/dailyworktask.model';
|
||||
import { ChangeProfileService } from './change-profile.service';
|
||||
import { SessionStore } from '../store/session.service';
|
||||
import { HttpService } from '../infra/http/http.service';
|
||||
import { Result } from 'neverthrow';
|
||||
import { HttpResult } from '../infra/http/type';
|
||||
|
||||
interface SignatureInputDTO {
|
||||
InstanceId: any;
|
||||
FolderId: any;
|
||||
DraftIds: any;
|
||||
OriginalFileName: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
@@ -22,7 +35,8 @@ export class ProcessesService {
|
||||
|
||||
constructor(
|
||||
private http: HttpClient,
|
||||
private changeProfileService: ChangeProfileService
|
||||
private changeProfileService: ChangeProfileService,
|
||||
private httpService: HttpService
|
||||
) {
|
||||
|
||||
this.loggeduser = SessionStore.user;
|
||||
@@ -249,6 +263,36 @@ export class ProcessesService {
|
||||
return this.http.post<any>(`${geturl}`, body, options)
|
||||
}
|
||||
|
||||
private baseUrl = `${environment.apiURLStage.slice(0, -1)}`;
|
||||
async createSignatureV2(input: SignatureInputDTO) {
|
||||
// Split DraftIds into an array
|
||||
const draftIds: String[] = input.DraftIds?.split(";").filter(Boolean) || [];
|
||||
|
||||
if (draftIds.length === 0) {
|
||||
throw new Error("No valid DraftIds provided");
|
||||
}
|
||||
// Run all requests in parallel
|
||||
const responses: Result<HttpResult<any>, HttpErrorResponse>[] = await Promise.all(
|
||||
draftIds.map(draftId =>
|
||||
this.httpService.put<any>(
|
||||
`${this.baseUrl}/Contents/${draftId}/signature/${SessionStore.user.UserId}`,
|
||||
input
|
||||
) as Promise<Result<HttpResult<any>, HttpErrorResponse>>
|
||||
)
|
||||
);
|
||||
|
||||
const failures = responses.filter(r => r.isErr() );
|
||||
|
||||
if (failures.length > 0) {
|
||||
// You can either throw or return both successes and failures
|
||||
throw new Error(
|
||||
`Some requests failed draft}`
|
||||
);
|
||||
}
|
||||
|
||||
return responses;
|
||||
}
|
||||
|
||||
CompleteTask(body: Excludetask) {
|
||||
|
||||
// double check
|
||||
|
||||
@@ -253,7 +253,9 @@ GetIdsPublicationNext(id:any){
|
||||
}
|
||||
|
||||
DeletePublication(folderId:any,publicationId:any){
|
||||
const geturl = environment.apiURL + 'presidentialActions/'+folderId+'/posts/'+publicationId;
|
||||
var baseUrl = `${environment.apiURLStage.slice(0, -1)}/PresidentialActions`;
|
||||
|
||||
const geturl = `${baseUrl}/${folderId}/Posts/${publicationId}`;
|
||||
let params = new HttpParams();
|
||||
params = params.set("folderId", folderId);
|
||||
params = params.set("id", publicationId);
|
||||
|
||||
@@ -1,71 +1,19 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import * as signalR from "@microsoft/signalr"
|
||||
import { SessionStore } from '../store/session.service';
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { HttpClient, HttpHeaders, HttpEventType } from '@angular/common/http';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { CMAPIService } from '../shared/repository/CMAPI/cmapi.service';
|
||||
import { HubConnectionBuilder } from '@microsoft/signalr';
|
||||
import { ok, err as Err, Result } from 'neverthrow';
|
||||
import { environment } from 'src/environments/environment';
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SocketConnectionMCRService {
|
||||
// private callbacks: Function[] = []
|
||||
// private onDisconnect: Function[] = []
|
||||
// private onConnect: Function[] = []
|
||||
|
||||
constructor(private http: HttpClient, private _CMAPIService: CMAPIService) {
|
||||
window["http"] = this.http
|
||||
}
|
||||
|
||||
// connect() {
|
||||
|
||||
// var connection = new signalR.HubConnectionBuilder()
|
||||
// .withUrl("https://gdcmapi-dev.dyndns.info/FileHub", {
|
||||
// accessTokenFactory: () => "Bearer "+SessionStore.user.Authorization
|
||||
// }).configureLogging(signalR.LogLevel.Information)
|
||||
// .build();
|
||||
|
||||
// connection.on("ReceiveMessage", (message) => {
|
||||
// console.log("ReceiveMessage", message)
|
||||
// })
|
||||
|
||||
// connection.onreconnected((connectionId) => {
|
||||
// console.assert(connection.state === signalR.HubConnectionState.Connected);
|
||||
// console.log(`Reconnected with connectionId: ${connectionId}`);
|
||||
// });
|
||||
|
||||
// connection.start()
|
||||
// .then(() => {
|
||||
// console.log("SignalR connection started.");
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// console.error("Error starting SignalR connection:", error);
|
||||
// });
|
||||
|
||||
// connection.onclose((error) => {
|
||||
// connection.start()
|
||||
// console.log("SignalR connection closed:", error);
|
||||
// });
|
||||
|
||||
// }
|
||||
|
||||
// subscribe(callback) {
|
||||
// this.callbacks.push(callback);
|
||||
// }
|
||||
|
||||
// unsubscribe(callback) {
|
||||
// this.callbacks = this.callbacks.filter(cb => cb !== callback);
|
||||
// }
|
||||
|
||||
// onDisconnectCallback(callback) {
|
||||
// this.onDisconnect.push(callback)
|
||||
// }
|
||||
// onConnectCallback(callback) {
|
||||
// this.onConnect.push(callback)
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
class ReconnectingWebSocketSignalR {
|
||||
@@ -81,7 +29,6 @@ class ReconnectingWebSocketSignalR {
|
||||
constructor() {}
|
||||
|
||||
connect() {
|
||||
console.log("try to connect=================================")
|
||||
this.stop = false;
|
||||
|
||||
// Limpar a conexão anterior, se existir
|
||||
@@ -98,53 +45,53 @@ class ReconnectingWebSocketSignalR {
|
||||
.configureLogging(signalR.LogLevel.Information)
|
||||
.build();
|
||||
|
||||
this.connection.start()
|
||||
.then(() => {
|
||||
this.isOpen = true;
|
||||
console.log('WebSocket connection established');
|
||||
this.onConnect.forEach(callback => callback());
|
||||
this.whenConnected.forEach(callback => callback());
|
||||
// this.connection.start()
|
||||
// .then(() => {
|
||||
// this.isOpen = true;
|
||||
// console.log('WebSocket connection established');
|
||||
// this.onConnect.forEach(callback => callback());
|
||||
// this.whenConnected.forEach(callback => callback());
|
||||
|
||||
}).catch((error) => {
|
||||
// }).catch((error) => {
|
||||
|
||||
console.error("Error starting SignalR connection:", error);
|
||||
// Adicione tratamento de erros detalhado conforme necessário
|
||||
// Exemplo: Verificar se o erro é devido à perda de conexão com a internet
|
||||
// console.error("Error starting SignalR connection:", error);
|
||||
// // Adicione tratamento de erros detalhado conforme necessário
|
||||
// // Exemplo: Verificar se o erro é devido à perda de conexão com a internet
|
||||
|
||||
if (error.message.includes("Failed to fetch")) {
|
||||
console.error("Erro de conexão com a internet");
|
||||
}
|
||||
// Tentar reconectar após um atraso
|
||||
if (!this.stop) {
|
||||
setTimeout(() => {
|
||||
this.connect();
|
||||
}, 1000); // Ajuste o atraso conforme necessário
|
||||
}
|
||||
});
|
||||
// if (error.message.includes("Failed to fetch")) {
|
||||
// console.error("Erro de conexão com a internet");
|
||||
// }
|
||||
// // Tentar reconectar após um atraso
|
||||
// if (!this.stop) {
|
||||
// setTimeout(() => {
|
||||
// this.connect();
|
||||
// }, 1000); // Ajuste o atraso conforme necessário
|
||||
// }
|
||||
// });
|
||||
|
||||
this.connection.on("ReceiveMessage", (message) => {
|
||||
// this.connection.on("ReceiveMessage", (message) => {
|
||||
|
||||
const data = JSON.parse(message);
|
||||
// const data = JSON.parse(message);
|
||||
|
||||
console.log("ReceiveMessage", data);
|
||||
// console.log("ReceiveMessage", data);
|
||||
|
||||
this.callbacks.forEach(callback => callback(data));
|
||||
// this.callbacks.forEach(callback => callback(data));
|
||||
|
||||
});
|
||||
// });
|
||||
|
||||
this.connection.onclose((error) => {
|
||||
console.log('WebSocket connection closed..');
|
||||
this.isOpen = false;
|
||||
this.onDisconnect.forEach(callback => callback());
|
||||
// Tentar reconectar após um atraso
|
||||
if (!this.stop && (!error || error.message !== "Connection stopped by client.")) {
|
||||
setTimeout(() => {
|
||||
this.connect();
|
||||
}, 3000); // Ajuste o atraso conforme necessário
|
||||
// this.connection.onclose((error) => {
|
||||
// console.log('WebSocket connection closed..');
|
||||
// this.isOpen = false;
|
||||
// this.onDisconnect.forEach(callback => callback());
|
||||
// // Tentar reconectar após um atraso
|
||||
// if (!this.stop && (!error || error.message !== "Connection stopped by client.")) {
|
||||
// setTimeout(() => {
|
||||
// this.connect();
|
||||
// }, 3000); // Ajuste o atraso conforme necessário
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
});
|
||||
// });
|
||||
}
|
||||
|
||||
commit(path): Promise<Result<true, false>> {
|
||||
@@ -218,188 +165,6 @@ class ReconnectingWebSocketSignalR {
|
||||
}
|
||||
}
|
||||
|
||||
interface socketResponse {
|
||||
index: string
|
||||
Guid: string
|
||||
IsCompleted: Boolean
|
||||
}
|
||||
// class ReconnectingWebSocket {
|
||||
|
||||
// private url: string
|
||||
// private socket
|
||||
// isOpen: boolean
|
||||
// private callbacks: Function[] = []
|
||||
// private onDisconnect: Function[] = []
|
||||
// private onConnect: Function[] = []
|
||||
// private whenConnected: Function[] = []
|
||||
// private stop = true
|
||||
// http: HttpClient = window["http"]
|
||||
|
||||
// constructor(url) {
|
||||
// this.url = url;
|
||||
// this.socket = null;
|
||||
// this.isOpen = false;
|
||||
// }
|
||||
|
||||
// connect() {
|
||||
// this.socket = new WebSocket(this.url);
|
||||
|
||||
// this.socket.addEventListener('open', (event) => {
|
||||
// this.isOpen = true;
|
||||
// console.log('WebSocket connection established');
|
||||
|
||||
// // Example: Send a message to the server
|
||||
// this.socket.send('Hello, WebSocket Server!');
|
||||
// this.onConnect.forEach(callback => callback());
|
||||
// this.whenConnected.forEach(callback => callback())
|
||||
// });
|
||||
|
||||
// this.socket.addEventListener('message', (event) => {
|
||||
// const data: socketResponse = JSON.parse(event.data)
|
||||
// this.callbacks.forEach(callback => callback(data));
|
||||
// });
|
||||
|
||||
// this.socket.addEventListener('close', (event) => {
|
||||
// console.log('WebSocket connection closed');
|
||||
// this.isOpen = false;
|
||||
// this.onDisconnect.forEach(callback => callback());
|
||||
// // Attempt to reconnect after a delay
|
||||
// if(this.stop == false) {
|
||||
// setTimeout(() => {
|
||||
// this.connect();
|
||||
// }, 1000); // Adjust the delay as needed
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// send(message) {
|
||||
// if (this.isOpen) {
|
||||
// this.socket.send(message);
|
||||
// } else {
|
||||
// console.error('WebSocket connection is not open. Unable to send message.');
|
||||
// }
|
||||
// }
|
||||
|
||||
// disconnect() {
|
||||
// this.stop = true
|
||||
// if (this.isOpen) {
|
||||
// this.isOpen = false;
|
||||
// this.socket.close();
|
||||
// }
|
||||
// }
|
||||
|
||||
// subscribe(callback) {
|
||||
// this.callbacks.push(callback);
|
||||
// }
|
||||
|
||||
// unsubscribe(callback) {
|
||||
// this.callbacks = this.callbacks.filter(cb => cb !== callback);
|
||||
// }
|
||||
|
||||
// onDisconnectCallback(callback) {
|
||||
// this.onDisconnect.push(callback)
|
||||
// }
|
||||
// onConnectCallback(callback) {
|
||||
// this.onConnect.push(callback)
|
||||
// }
|
||||
|
||||
// registerWhenConnected(f: Function) {
|
||||
// if(this.isOpen) {
|
||||
// f();
|
||||
// } else {
|
||||
// this.whenConnected.push(f);
|
||||
// }
|
||||
|
||||
// }
|
||||
// }
|
||||
|
||||
// export class ObjectMergeNotification{
|
||||
|
||||
// socket = new ReconnectingWebSocket('ws://localhost:3002');
|
||||
// callbacks: {[GUID: string]: Function} = {}
|
||||
// runWatch = true
|
||||
// CMAPIService: CMAPIService = window["CMAPIAPIRepository"]
|
||||
// watchCount = 0
|
||||
|
||||
// constructor() {
|
||||
// this.socket.onDisconnectCallback(()=> {
|
||||
// console.log("run watch")
|
||||
// this.runWatch = true
|
||||
// this.watch()
|
||||
// })
|
||||
|
||||
// this.socket.onConnectCallback(()=> {
|
||||
// console.log("open trigger")
|
||||
// this.runWatch = false
|
||||
// })
|
||||
|
||||
// this.socket.subscribe((data: socketResponse) => {
|
||||
// if(data.IsCompleted == true) {
|
||||
// console.log("==================!!!====================")
|
||||
// try {
|
||||
// this.callbacks[data.Guid](data)
|
||||
// delete this.callbacks[data.Guid]
|
||||
// } catch (error) {}
|
||||
// } else {
|
||||
// console.log("else", data)
|
||||
// }
|
||||
// })
|
||||
|
||||
// this.watch()
|
||||
// }
|
||||
|
||||
// connect() {
|
||||
// this.socket.connect()
|
||||
// }
|
||||
|
||||
// async watch() {
|
||||
|
||||
// this.watchCount = 0;
|
||||
|
||||
// if(this.runWatch) {
|
||||
// setTimeout(async () => {
|
||||
// for(const [key, funx] of Object.entries(this.callbacks)) {
|
||||
|
||||
// const request = await this.CMAPIService.getVideoHeader(key)
|
||||
|
||||
// if(request.isOk()) {
|
||||
// funx()
|
||||
// delete this.callbacks[key]
|
||||
// }
|
||||
// }
|
||||
|
||||
// this.watchCount++
|
||||
// if(this.watchCount <= 15) {
|
||||
// this.watch()
|
||||
// } else {
|
||||
// this.runWatch = false
|
||||
// }
|
||||
|
||||
// }, 1000)
|
||||
|
||||
|
||||
// } else {
|
||||
// console.log("end loop============================")
|
||||
// }
|
||||
// }
|
||||
|
||||
// close() {
|
||||
// this.socket.disconnect();
|
||||
// this.watchCount = 0;
|
||||
// this.runWatch = false
|
||||
// }
|
||||
|
||||
// subscribe(GUID, callback:Function) {
|
||||
// this.callbacks[GUID] = callback;
|
||||
// }
|
||||
|
||||
// unsubscribe(GUID) {
|
||||
// delete this.callbacks[GUID]
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
|
||||
export class ObjectMergeNotification{
|
||||
|
||||
socket = new ReconnectingWebSocketSignalR()
|
||||
@@ -457,9 +222,6 @@ export class ObjectMergeNotification{
|
||||
|
||||
}, 1000)
|
||||
|
||||
|
||||
} else {
|
||||
console.log("end loop============================")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -29,7 +29,7 @@ export class EventDetailsDocumentsOptionsPage implements OnInit {
|
||||
private navParams: NavParams,
|
||||
private processService: ProcessesService,
|
||||
private erroHandler: HttpErrorHandle,
|
||||
|
||||
|
||||
private processes: ProcessesService,
|
||||
private toastService: ToastService,
|
||||
public TaskService: TaskService,
|
||||
@@ -102,7 +102,7 @@ export class EventDetailsDocumentsOptionsPage implements OnInit {
|
||||
},(error) => {
|
||||
this.erroHandler.httpStatusHandle(error)
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
|
||||
async Assinar() {
|
||||
@@ -144,7 +144,7 @@ export class EventDetailsDocumentsOptionsPage implements OnInit {
|
||||
cssClass: "popup-question discart-expedient-modal",
|
||||
backdropDismiss: true
|
||||
});
|
||||
|
||||
|
||||
modal.onDidDismiss().then(async (res) => {
|
||||
const data = res.data
|
||||
if(data == "Yes") {
|
||||
@@ -156,14 +156,14 @@ export class EventDetailsDocumentsOptionsPage implements OnInit {
|
||||
"DraftIds": this.DraftIds,
|
||||
"OriginalFileName": this.DraftNames
|
||||
}
|
||||
|
||||
|
||||
const loader = this.toastService.loading()
|
||||
|
||||
|
||||
|
||||
|
||||
try {
|
||||
await this.processes.presidentialActionsSignature(body).toPromise()
|
||||
|
||||
await this.Assinar();
|
||||
await this.processes.createSignatureV2(body);
|
||||
|
||||
//await this.Assinar();
|
||||
this.TaskService.loadDiplomas();
|
||||
this.goBackRoute();
|
||||
} catch (error) {
|
||||
@@ -173,13 +173,13 @@ export class EventDetailsDocumentsOptionsPage implements OnInit {
|
||||
loader.remove()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}, (error) => {
|
||||
console.log(error)
|
||||
});
|
||||
|
||||
|
||||
await modal.present();
|
||||
|
||||
|
||||
}
|
||||
|
||||
goBackRoute() {
|
||||
|
||||
@@ -5,10 +5,10 @@ import { PublicationFolder } from 'src/app/models/publicationfolder';
|
||||
import { PublicationsService } from 'src/app/services/publications.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { HttpErrorHandle } from 'src/app/services/http-error-handle.service';
|
||||
|
||||
import { NgxMatDateFormats } from '@angular-material-components/datetime-picker';
|
||||
import { NGX_MAT_DATE_FORMATS } from '@angular-material-components/datetime-picker';
|
||||
|
||||
import { SessionStore } from 'src/app/store/session.service';
|
||||
import { ActionRemoteRepositoryService } from 'src/app/module/actions/data/repository/action-remote-repository.service';
|
||||
const CUSTOM_DATE_FORMATS: NgxMatDateFormats = {
|
||||
parse: {
|
||||
dateInput: "YYYY-MMMM-DD HH:mm"
|
||||
@@ -60,9 +60,8 @@ export class EditActionPage implements OnInit {
|
||||
private publicationsService: PublicationsService,
|
||||
private toastService: ToastService,
|
||||
private httpErrorHandle: HttpErrorHandle,
|
||||
) {
|
||||
|
||||
}
|
||||
private actionRemoteRepository: ActionRemoteRepositoryService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.getPublicationDetail();
|
||||
@@ -73,11 +72,8 @@ export class EditActionPage implements OnInit {
|
||||
}
|
||||
|
||||
getPublicationDetail() {
|
||||
|
||||
this.publicationsService.GetPresidentialAction(this.folderId).subscribe( res => {
|
||||
this.folder = res;
|
||||
console.log('FOLDER',this.folder)
|
||||
|
||||
|
||||
this.dateControlStart = new FormControl(moment(new Date(this.folder.DateBegin)));
|
||||
this.dateControlEnd = new FormControl(moment(new Date(this.folder.DateEnd)));
|
||||
@@ -116,29 +112,27 @@ export class EditActionPage implements OnInit {
|
||||
this.injectValidation();
|
||||
this.runValidation();
|
||||
|
||||
let body = {
|
||||
ProcessId: this.folderId,
|
||||
Description: this.folder.Description,
|
||||
Detail: this.folder.Detail,
|
||||
DateBegin: this.folder.DateBegin,
|
||||
DateEnd: this.folder.DateEnd,
|
||||
ActionType: this.folder.ActionType,
|
||||
}
|
||||
|
||||
const loader = this.toastService.loading()
|
||||
|
||||
try {
|
||||
await this.publicationsService.UpdatePresidentialAction(body).toPromise()
|
||||
this.close();
|
||||
this.updateDesktopComponent.emit();
|
||||
this.httpErrorHandle.httpsSucessMessagge('Editar Acção')
|
||||
this.getActions.emit()
|
||||
var result = await this.actionRemoteRepository.update({
|
||||
userId: SessionStore.user.UserId,
|
||||
description: this.folder.Description,
|
||||
detail: this.folder.Detail,
|
||||
location: "string",
|
||||
dateBegin: this.folder.DateBegin,
|
||||
dateEnd: this.folder.DateEnd,
|
||||
actionType: "Evento",
|
||||
processId: this.folder.ProcessId as any,
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
this.httpErrorHandle.httpStatusHandle(error)
|
||||
} finally {
|
||||
loader.remove()
|
||||
if(result.isOk()) {
|
||||
this.close();
|
||||
this.httpErrorHandle.httpsSucessMessagge('Editar Acção');
|
||||
this.getActions.emit()
|
||||
} else {
|
||||
this.httpErrorHandle.httpStatusHandle(result.error)
|
||||
}
|
||||
|
||||
loader.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,17 +4,6 @@
|
||||
<ion-label class="title"> Nova Acção</ion-label> <br>
|
||||
<i style="margin-top: -3px; font-size: 15px;" > Campos marcados com * são obrigatórios</i>
|
||||
</div>
|
||||
<!-- <div class="actionType">
|
||||
<ion-segment [(ngModel)]="segment" (ionChange)="segmentChanged($event)">
|
||||
<ion-segment-button value="Viagem">
|
||||
<ion-label>Viagem</ion-label>
|
||||
</ion-segment-button>
|
||||
<ion-segment-button value="Evento">
|
||||
<ion-label>Evento</ion-label>
|
||||
</ion-segment-button>
|
||||
</ion-segment>
|
||||
</div> -->
|
||||
|
||||
</div>
|
||||
</ion-header>
|
||||
|
||||
@@ -31,16 +20,6 @@
|
||||
<ion-icon slot="start" src="assets/images/icons-calendar.svg"></ion-icon>
|
||||
</div>
|
||||
<div class="ion-input-class flex-grow-1">
|
||||
<!-- <ion-datetime
|
||||
class="d-block d-md-none"
|
||||
[(ngModel)]="folder.DateBegin"
|
||||
placeholder="Início"
|
||||
displayFormat="D MMM YYYY H:mm"
|
||||
minuteValues="0,5,10,15,20,25,30,35,40,45,50,55"
|
||||
monthShortNames="Jan, Fev, Mar, Abr, Mai, Jun, Jul, Aug, Sep, Out, Nov, Dez"
|
||||
max="2025">
|
||||
</ion-datetime> -->
|
||||
|
||||
<mat-form-field appearance="none" class="width-100 date-hour-picker d-md-block">
|
||||
<input matInput [ngxMatDatetimePicker]="picker1"
|
||||
placeholder="Data inicio*"
|
||||
@@ -68,15 +47,6 @@
|
||||
<ion-icon slot="start" src="assets/images/icons-calendar.svg"></ion-icon>
|
||||
</div>
|
||||
<div class="ion-input-class d-flex flex-grow-1">
|
||||
<!-- <ion-datetime
|
||||
class="flex-grow-1 d-md-none"
|
||||
[(ngModel)]="folder.DateEnd"
|
||||
placeholder="Fim"
|
||||
displayFormat="D MMM YYYY H:mm"
|
||||
minuteValues="0,5,10,15,20,25,30,35,40,45,50,55"
|
||||
monthShortNames="Jan, Fev, Mar, Abr, Mai, Jun, Jul, Aug, Sep, Out, Nov, Dez"
|
||||
max="2025">
|
||||
</ion-datetime> -->
|
||||
|
||||
<mat-form-field appearance="none" class="width-100 date-hour-picker d-md-block">
|
||||
<input matInput [ngxMatDatetimePicker]="picker2"
|
||||
@@ -127,6 +97,6 @@
|
||||
<ion-label>Cancelar</ion-label>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
|
||||
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
|
||||
@@ -19,8 +19,6 @@ const CUSTOM_DATE_FORMATS: NgxMatDateFormats = {
|
||||
monthYearA11yLabel: "MMMM YYYY"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-new-action',
|
||||
templateUrl: './new-action.page.html',
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
<ion-header class="ion-no-border background-white px-20 pt-25">
|
||||
<div class="title-content d-flex">
|
||||
<!-- <div class="back-icon">
|
||||
<ion-icon class="font-35-rem" (click)="goBack()" slot="end" src='assets/images/icons-arrow-arrow-left.svg'></ion-icon>
|
||||
</div> -->
|
||||
<div class="div-title" >
|
||||
<ion-label class="title">{{ publicationTitle }}</ion-label> <br>
|
||||
<i style="margin-top: -3px; font-size: 15px;"> Campos marcados com * são obrigatórios</i>
|
||||
@@ -16,7 +13,7 @@
|
||||
|
||||
<div *ngIf="publicationType!='1'" class="ion-item-container"
|
||||
[class.input-error]="Form?.get('Subject')?.invalid && validateFrom ">
|
||||
<ion-input autocomplete="on" autocorrect="on" spellcheck="true" [(ngModel)]="PublicationFromMvService.form.Title" name="title"
|
||||
<ion-input autocomplete="on" autocorrect="on" spellcheck="true" [(ngModel)]="data.title" name="title"
|
||||
placeholder="Título*"></ion-input>
|
||||
</div>
|
||||
|
||||
@@ -27,48 +24,47 @@
|
||||
</div>
|
||||
<div class="ion-textarea-class flex-grow-1"
|
||||
[class.input-error]="Form?.get('Message')?.invalid && validateFrom ">
|
||||
<ion-textarea autocomplete="on" autocorrect="on" spellcheck="true" [(ngModel)]="PublicationFromMvService.form.Message"
|
||||
<ion-textarea autocomplete="on" autocorrect="on" spellcheck="true" [(ngModel)]="data.message"
|
||||
name="description" ngDefaultControl rows="12" cols="20" placeholder="Corpo de texto*"></ion-textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- <div *ngIf="publication">
|
||||
OriginalFileName: {{ publication.OriginalFileName }}
|
||||
</div> -->
|
||||
|
||||
|
||||
<!-- Captured -->
|
||||
<div *ngIf="PublicationFromMvService.form.Files.length > 0">
|
||||
<div *ngIf="data.files.length > 0">
|
||||
<ion-label class="attached-title pb-10">Anexos</ion-label>
|
||||
<div>
|
||||
<div class="d-flex" >
|
||||
|
||||
<div *ngFor="let seleted of PublicationFromMvService.form.Files.slice(0, displayLimit), let i = index" lot="start" class="mr-10">
|
||||
<div *ngFor="let seleted of data.files.slice(0, displayLimit), let i = index" lot="start" class="mr-10">
|
||||
|
||||
<div>
|
||||
|
||||
<div class="text-center cursor-pointer" (click)="deleteFromSeletedContent(i)" style="font-weight: 700;color: #c63527; text-align-last: right;">
|
||||
<div class="text-center cursor-pointer" (click)="deleteFromSeletedContent(i, seleted)" style="font-weight: 700;color: #c63527; text-align-last: right;">
|
||||
X
|
||||
</div>
|
||||
|
||||
<div *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' && seleted.chucksManager">
|
||||
|
||||
<mat-progress-bar
|
||||
|
||||
mode="determinate"
|
||||
[style.width]="seleted.chucksManager.uploadPercentage"
|
||||
></mat-progress-bar>
|
||||
<div *ngIf="checkFileType.checkFileType(seleted.fileExtension) == 'video' && seleted.chucksManager">
|
||||
|
||||
</div>
|
||||
|
||||
<ion-img *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'image'"
|
||||
name="image" ngDefaultControl [src]="seleted.url" style="height: 69px; width: 69px;"></ion-img>
|
||||
<ion-img
|
||||
*ngIf="checkFileType.checkFileType(seleted.fileExtension) == 'image'"
|
||||
name="image"
|
||||
ngDefaultControl
|
||||
[src]="'data:image/' + seleted.fileExtension + ';base64,' + seleted.fileBase64"
|
||||
style="height: 69px; width: 69px;">
|
||||
</ion-img>
|
||||
|
||||
<video class="sdf" *ngIf="checkFileType.checkFileType(seleted.FileExtension) == 'video' " width="70" height="70"
|
||||
preload="metadata" webkit-playsinline="webkit-playsinline">
|
||||
<source type="video/mp4" [src]="seleted.url">
|
||||
<video class="sdf"
|
||||
*ngIf="checkFileType.checkFileType(seleted.fileExtension) == 'video'"
|
||||
width="70" height="70"
|
||||
preload="metadata"
|
||||
webkit-playsinline="webkit-playsinline"
|
||||
controls>
|
||||
<source
|
||||
[src]="getSafeVideoUrl(seleted)"
|
||||
[type]="'video/' + seleted.fileExtension">
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
|
||||
</div>
|
||||
@@ -76,15 +72,10 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- <button class="btn-no-color" (click)="clear()">
|
||||
<ion-icon name="close"></ion-icon>
|
||||
</button> -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div *ngIf="checkTableDivice()" style="display: flex;">
|
||||
<div (click)="chossePhotoOrVideo()">
|
||||
<div class="attach-icon">
|
||||
@@ -102,7 +93,7 @@
|
||||
|
||||
<div *ngIf="photoOrVideo" class="container-multiselect pt-10" style="width: 200px;">
|
||||
<button id="container-multiselect" class="multiselect-button" (click)="takePicture()">Fotografia</button>
|
||||
<button id="container-multiselect" class="multiselect-button" (click)="startVideoRecording()">Video</button>
|
||||
<!-- <button id="container-multiselect" class="multiselect-button" (click)="startVideoRecording()">Video</button> -->
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { PublicationsService } from 'src/app/services/publications.service';
|
||||
import { Publication } from 'src/app/models/publication';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { ThemeService } from 'src/app/services/theme.service';
|
||||
@@ -9,18 +8,17 @@ import { HttpErrorHandle } from 'src/app/services/http-error-handle.service';
|
||||
import { PublicationFolderService } from 'src/app/store/publication-folder.service';
|
||||
import { FilePicker } from '@capawesome/capacitor-file-picker';
|
||||
import { checkFileTypeService } from 'src/app/services/checkFileType.service';
|
||||
import { FileValidatorService } from "src/app/services/file/file-validator.service";
|
||||
import { MiddlewareServiceService } from "src/app/shared/API/middleware/middleware-service.service";
|
||||
import { LakefsRepositoryService } from '../../repository/lakefs/lakefs-repository.service';
|
||||
|
||||
import { CaptureImageOptions, MediaCapture } from '@awesome-cordova-plugins/media-capture/ngx';
|
||||
import { Directory, Filesystem, FilesystemDirectory } from '@capacitor/filesystem';
|
||||
import { ModalController, Platform } from '@ionic/angular';
|
||||
import { PublicationAttachmentEntity } from '../upload/upload-streaming.service';
|
||||
import { VideoconvertService } from 'src/app/services/videoconvert.service';
|
||||
import { PublicationHolderService } from 'src/app/services/publication/publication-holder.service'
|
||||
import { PublicationFromMvService } from "src/app/shared/publication/upload/publication-from-mv.service"
|
||||
import { UploadStreamingService } from "src/app/shared/publication/upload/upload-streaming.service"
|
||||
import { PublicationCreateUseCaseService } from "src/app/core/actions/use-case/publication-create-use-case.service";
|
||||
import { PublicationUpdateUseCaseService } from 'src/app/core/actions/use-case/publication-update-use-case.service';
|
||||
import { PublicationFilesDeleteByPathUseCaseService } from 'src/app/core/actions/use-case/publication-files-delete-by-path-use-case.service';
|
||||
import { DomSanitizer} from '@angular/platform-browser';
|
||||
enum ActionType {
|
||||
newRapid = "1",
|
||||
new = "2",
|
||||
@@ -43,7 +41,7 @@ export class NewPublicationPage implements OnInit {
|
||||
Form: FormGroup;
|
||||
validateFrom = false
|
||||
|
||||
@Input() publication!: Publication;
|
||||
@Input() publication!: IPublication;
|
||||
@Input() publicationType: ActionType;
|
||||
@Input() folderId: string;
|
||||
@Input() documentId: string;
|
||||
@@ -54,7 +52,6 @@ export class NewPublicationPage implements OnInit {
|
||||
@Output() goBacktoPublicationDetails = new EventEmitter<any>();
|
||||
|
||||
guestPicture: any;
|
||||
|
||||
capturedImage: any = '';
|
||||
capturedImageTitle: any = '';
|
||||
fileType: string;
|
||||
@@ -65,6 +62,18 @@ export class NewPublicationPage implements OnInit {
|
||||
photoOrVideo: boolean = false;
|
||||
video: any;
|
||||
|
||||
data: PublicationCreateInputDto & PublicationUpdateInputDto = {
|
||||
userId: SessionStore.user.UserId,
|
||||
dateIndex: new Date().toISOString(),
|
||||
title: "",
|
||||
message: "",
|
||||
datePublication: new Date().toISOString(),
|
||||
files: [],
|
||||
organicEntityId: 101,
|
||||
};
|
||||
|
||||
deleteFiles: IPublicationDocument[] = [];
|
||||
|
||||
constructor(
|
||||
public PublicationFromMvService: PublicationFromMvService,
|
||||
private publications: PublicationsService,
|
||||
@@ -78,73 +87,63 @@ export class NewPublicationPage implements OnInit {
|
||||
private platform: Platform,
|
||||
private videoconvertService: VideoconvertService,
|
||||
public UploadStreamingService: UploadStreamingService,
|
||||
private modalController: ModalController
|
||||
private modalController: ModalController,
|
||||
private publicationCreateUseCaseService: PublicationCreateUseCaseService,
|
||||
private publicationFileGetByDocumentIdService: PublicationFileGetByDocumentIdService,
|
||||
private local: PublicationFileLocalRepositoryService,
|
||||
private PublicationUpdateUseCaseService: PublicationUpdateUseCaseService,
|
||||
private PublicationFilesDeleteByPathUseCaseService: PublicationFilesDeleteByPathUseCaseService,
|
||||
public sanitizer: DomSanitizer,
|
||||
) {
|
||||
this.publicationTitle = 'Nova Publicação';
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.PublicationFromMvService.clear()
|
||||
this.setAction();
|
||||
this.setData()
|
||||
this.data.processId = this.folderId as any;
|
||||
this.processData();
|
||||
}
|
||||
|
||||
setData() {
|
||||
if(this.publication) {
|
||||
this.processData(this.publication)
|
||||
} else {
|
||||
this.getPublicationDetail()
|
||||
}
|
||||
}
|
||||
|
||||
getPublicationDetail() {
|
||||
if (this.publicationType != ActionType.new) {
|
||||
this.showLoader = true;
|
||||
this.publications.GetPublicationWithArrayOfFilesById(this.documentId).subscribe(res => {
|
||||
this.processData(res)
|
||||
processData() {
|
||||
if (this.publicationType == ActionType.edit) {
|
||||
|
||||
console.log("res get", res)
|
||||
this.showLoader = false;
|
||||
}, (error) => {
|
||||
console.log(error)
|
||||
this.showLoader = false;
|
||||
this.goBack()
|
||||
});
|
||||
}
|
||||
}
|
||||
this.data.title = this.publication.title;
|
||||
this.data.message = this.publication.message;
|
||||
this.data.documentId = this.publication.documentId;
|
||||
this.data.processId = this.publication.processId;
|
||||
this.data.datePublication = this.publication.datePublication;
|
||||
this.data.userId = this.publication.userId;
|
||||
this.data.organicEntityId = this.publication.organicEntityId;
|
||||
this.data.dateIndex = this.publication.dateIndex;
|
||||
|
||||
processData(res) {
|
||||
this.local.find({documentId: this.publication.documentId}).then(async e => {
|
||||
if(e.isOk() && e.value.length == 0) {
|
||||
var result = await this.publicationFileGetByDocumentIdService.execute({
|
||||
documentId: this.publication.documentId,
|
||||
processId: this.publication.processId,
|
||||
datePublication: this.publication.datePublication
|
||||
});
|
||||
|
||||
console.log("res process", res)
|
||||
this.PublicationFromMvService.form.Files = []
|
||||
this.PublicationFromMvService.form.setData({
|
||||
DateIndex: res.DateIndex,
|
||||
DocumentId: res.DocumentId,
|
||||
ProcessId: res.ProcessId,
|
||||
Title: res.Title,
|
||||
Message: res.Message,
|
||||
DatePublication: res.DatePublication
|
||||
})
|
||||
|
||||
if (res.Files && Array.isArray(res?.Files)) {
|
||||
|
||||
const newFiles: PublicationAttachmentEntity[] = res.Files.map(e => {
|
||||
return new PublicationAttachmentEntity(
|
||||
{
|
||||
base64: e.FileBase64,
|
||||
extension: e.FileExtension,
|
||||
OriginalFileName: e.OriginalFileName,
|
||||
FileType: this.checkFileType.checkFileType(e.FileExtension) as any
|
||||
if(result.isOk()) {
|
||||
this.data.files = result.value.added.map(file => ({
|
||||
fileBase64: file.file,
|
||||
fileExtension: file.extension,
|
||||
originalFileName: "NoUploadNeed",
|
||||
...file
|
||||
}));
|
||||
}
|
||||
)
|
||||
} else if(e.isOk()) {
|
||||
console.log(e.value);
|
||||
this.data.files = e.value.map(file => ({
|
||||
fileBase64: file.file,
|
||||
fileExtension: file.extension,
|
||||
originalFileName: "NoUploadNeed",
|
||||
...file
|
||||
}));
|
||||
}
|
||||
})
|
||||
|
||||
for(const files of newFiles) {
|
||||
this.PublicationFromMvService.form.Files.push(files)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async takePicture() {
|
||||
@@ -159,27 +158,6 @@ export class NewPublicationPage implements OnInit {
|
||||
this.capturedImageTitle = 'foto';
|
||||
|
||||
this.showCroppModal()
|
||||
/* if(validation.isOk) { */
|
||||
/* const compressedImage = await this.compressImageBase64(
|
||||
this.capturedImage,
|
||||
800, // maxWidth
|
||||
800, // maxHeight
|
||||
0.9 // quality
|
||||
).then((picture) => {
|
||||
this.photoOrVideo = false;
|
||||
|
||||
const FileExtension = this.removeTextBeforeSlash('jpeg', '/')
|
||||
|
||||
const newAttachment = new PublicationAttachmentEntity(
|
||||
{
|
||||
base64: picture,
|
||||
extension: FileExtension,
|
||||
OriginalFileName: "foto",
|
||||
FileType: 'image'
|
||||
}
|
||||
)
|
||||
this.PublicationFromMvService.form.Files.push(newAttachment)
|
||||
}); */
|
||||
}
|
||||
|
||||
async laodPicture() {
|
||||
@@ -211,8 +189,6 @@ export class NewPublicationPage implements OnInit {
|
||||
FileType: 'image'
|
||||
}
|
||||
)
|
||||
//newAttachment.needUpload();
|
||||
|
||||
this.PublicationFromMvService.form.Files.push(newAttachment)
|
||||
});
|
||||
|
||||
@@ -225,8 +201,6 @@ export class NewPublicationPage implements OnInit {
|
||||
multiple: true,
|
||||
});
|
||||
|
||||
console.log(result)
|
||||
|
||||
result.files.forEach(async blobFile => {
|
||||
console.log(blobFile)
|
||||
if (this.checkFileType.checkFileType(blobFile.mimeType) == 'image') {
|
||||
@@ -241,31 +215,16 @@ export class NewPublicationPage implements OnInit {
|
||||
}).catch((erro) => {
|
||||
console.log(erro)
|
||||
})
|
||||
} else if (this.checkFileType.checkFileType(blobFile.mimeType) == 'video'){
|
||||
|
||||
let convertedVideo = await this.videoconvertService.convertVideoWeb(blobFile.blob,"src/assets/videos/","output",'mp4')
|
||||
} else if (this.checkFileType.checkFileType(blobFile.mimeType) == 'video') {
|
||||
|
||||
this.convertBlobToBase64(blobFile.blob).then((value: string) => {
|
||||
|
||||
this.filesSizeSum = this.filesSizeSum + blobFile.size
|
||||
this.data.files.push({
|
||||
fileBase64: this.removeTextBeforeSlash(value, ','),
|
||||
fileExtension: 'mp4',
|
||||
originalFileName: "image",
|
||||
})
|
||||
|
||||
const FileExtension = this.removeTextBeforeSlash(blobFile.mimeType, '/')
|
||||
|
||||
const file = new File([blobFile.blob], blobFile.name);
|
||||
|
||||
const newAttachment = new PublicationAttachmentEntity(
|
||||
{
|
||||
base64: this.removeTextBeforeSlash(value, ','),
|
||||
extension: 'mp4',
|
||||
blobFile: file,
|
||||
FileType: this.checkFileType.checkFileType(FileExtension) as any,
|
||||
OriginalFileName: 'load video'
|
||||
}
|
||||
)
|
||||
|
||||
newAttachment.needUpload()
|
||||
this.PublicationFromMvService.form.Files.push(newAttachment)
|
||||
this.filecontent = true;
|
||||
}).catch((erro) => {
|
||||
console.log(erro)
|
||||
})
|
||||
@@ -277,6 +236,11 @@ export class NewPublicationPage implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
getSafeVideoUrl(file: { fileExtension: string, fileBase64: string }): SafeResourceUrl {
|
||||
const unsafeUrl = 'data:video/' + file.fileExtension + ';base64,' + file.fileBase64;
|
||||
return this.sanitizer.bypassSecurityTrustResourceUrl(unsafeUrl);
|
||||
}
|
||||
|
||||
async loadVideoTablet() {
|
||||
|
||||
const result = await FilePicker.pickMedia
|
||||
@@ -340,11 +304,10 @@ export class NewPublicationPage implements OnInit {
|
||||
injectValidation() {
|
||||
|
||||
this.Form = new FormGroup({
|
||||
Subject: new FormControl(this.PublicationFromMvService.form.Title, [
|
||||
Subject: new FormControl(this.data.title, [
|
||||
Validators.required,
|
||||
// Validators.minLength(4)
|
||||
]),
|
||||
Message: new FormControl(this.PublicationFromMvService.form.Message, [
|
||||
Message: new FormControl(this.data.message, [
|
||||
Validators.required,
|
||||
Validators.maxLength(1000)
|
||||
])
|
||||
@@ -361,12 +324,24 @@ export class NewPublicationPage implements OnInit {
|
||||
return false
|
||||
}
|
||||
|
||||
this.PublicationFromMvService.setFolderId(this.folderId)
|
||||
this.PublicationFromMvService.setFolderId(this.folderId)
|
||||
this.goBack();
|
||||
await this.PublicationFromMvService.save()
|
||||
this.data.datePublication = new Date().toISOString();
|
||||
|
||||
// this.PublicationHolderService.setPublication(this.PublicationFromMvService)
|
||||
if (this.publicationType == ActionType.edit) {
|
||||
this.data.files = this.data.files.filter(e => e.originalFileName != 'NoUploadNeed');
|
||||
|
||||
this.PublicationUpdateUseCaseService.execute(this.data).then(async res => {
|
||||
for(var e of this.deleteFiles) {
|
||||
await this.PublicationFilesDeleteByPathUseCaseService.execute(e)
|
||||
}
|
||||
this.PublicationFolderService.loadPublications(this.folderId as any);
|
||||
});
|
||||
} else {
|
||||
this.publicationCreateUseCaseService.execute(this.data).then(res => {
|
||||
this.PublicationFolderService.loadPublications(this.folderId as any);
|
||||
});
|
||||
}
|
||||
|
||||
this.goBack();
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
@@ -409,14 +384,7 @@ export class NewPublicationPage implements OnInit {
|
||||
}
|
||||
|
||||
async goBack() {
|
||||
|
||||
if (this.publicationType == ActionType.new) {
|
||||
this.goBackToViewPublications.emit();
|
||||
} else {
|
||||
this.goBackToViewPublications.emit();
|
||||
//this.goBacktoPublicationDetails.emit();
|
||||
}
|
||||
|
||||
this.goBackToViewPublications.emit();
|
||||
}
|
||||
|
||||
async compressImageBase64(base64String: string, maxWidth: number, maxHeight: number, quality: number): Promise<string> {
|
||||
@@ -496,19 +464,6 @@ export class NewPublicationPage implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* convertBlobToBase64(blob: Blob) {
|
||||
console.log('Convert blob ',blob)
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader;
|
||||
reader.onerror = reject;
|
||||
reader.onload = () => {
|
||||
resolve(reader.result)
|
||||
}
|
||||
reader.readAsDataURL(blob)
|
||||
},)
|
||||
} */
|
||||
|
||||
getBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
@@ -632,8 +587,13 @@ export class NewPublicationPage implements OnInit {
|
||||
return parseInt(sizeInMB)
|
||||
}
|
||||
|
||||
deleteFromSeletedContent(index) {
|
||||
this.PublicationFromMvService.form.Files.splice(index, 1)
|
||||
deleteFromSeletedContent(index, file?: IPublicationDocument) {
|
||||
this.data.files.splice(index, 1)
|
||||
|
||||
if(this.publicationType == ActionType.edit) {
|
||||
this.deleteFiles.push(file!);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
chossePhotoOrVideo() {
|
||||
@@ -781,16 +741,13 @@ console.log(stringGerada);
|
||||
this.filecontent = true;
|
||||
this.photoOrVideo = false;
|
||||
|
||||
const newAttachment = new PublicationAttachmentEntity(
|
||||
{
|
||||
base64: res.data.base64ToCroppe,
|
||||
extension: 'jpeg',
|
||||
OriginalFileName: "image",
|
||||
FileType: 'image'
|
||||
}
|
||||
)
|
||||
// console.log(res.data.base64ToCroppe);
|
||||
|
||||
this.PublicationFromMvService.form.Files.push(newAttachment)
|
||||
this.data.files.push({
|
||||
fileBase64: res.data.base64ToCroppe.split(",")[1],
|
||||
fileExtension: 'jpeg',
|
||||
originalFileName: "image",
|
||||
})
|
||||
}
|
||||
}, (error) => {
|
||||
console.log(error)
|
||||
@@ -798,14 +755,6 @@ console.log(stringGerada);
|
||||
|
||||
await modal.present();
|
||||
|
||||
// let fileObject = new PublicationAttachmentEntity({
|
||||
// base64: this.removeTextBeforeSlash(this.capturedImage, ',') ,
|
||||
// extension: 'jpeg',
|
||||
// OriginalFileName: 'video',
|
||||
// FileType: 'image'
|
||||
// })
|
||||
// this.PublicationFromMvService.form.Files.push(fileObject)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -814,6 +763,15 @@ console.log(stringGerada);
|
||||
import { Observable, of, Subject } from 'rxjs';
|
||||
import { tap, switchMap, delay, map } from 'rxjs/operators';
|
||||
import { CropImagePage } from 'src/app/modals/crop-image/crop-image.page';
|
||||
import { PublicationCreateInputDto } from 'src/app/core/actions/use-case/publication-create-use-case.service';
|
||||
import { SessionStore } from 'src/app/store/session.service';
|
||||
import { IPublication } from 'src/app/core/actions/entity/publicationEntity';
|
||||
import { PublicationFileGetByDocumentIdService } from 'src/app/core/actions/use-case/publication-file-get-by-document-id.service';
|
||||
import { PublicationFileLocalRepositoryService } from 'src/app/module/actions/data/repository/publication-file-local-repository.service';
|
||||
import { PublicationUpdateInputDto } from 'src/app/core/actions/use-case/publication-update-use-case.service';
|
||||
import { days } from '../../../models/agenda/AgendaEventList';
|
||||
import { IPublicationDocument } from 'src/app/core/actions/entity/publicationDocument';
|
||||
import { SafeResourceUrl } from '@angular/platform-browser';
|
||||
|
||||
function shareResponse(): MethodDecorator {
|
||||
return function (
|
||||
|
||||
@@ -9,10 +9,7 @@ import { ObjectMergeNotification } from 'src/app/services/socket-connection-mcr.
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { Result } from 'neverthrow';
|
||||
import { IPublicationFormModelEntity } from '../new-publication/interface/interface';
|
||||
import { CMAPIService } from "src/app/shared/repository/CMAPI/cmapi.service"
|
||||
import { App } from '@capacitor/app';
|
||||
import { ModalController, NavParams, Platform, LoadingController } from '@ionic/angular';
|
||||
import { Router } from '@angular/router';
|
||||
import { ModalController, Platform } from '@ionic/angular';
|
||||
|
||||
enum ActionType {
|
||||
newRapid = "1",
|
||||
@@ -33,23 +30,16 @@ export class PublicationFromMvService {
|
||||
publicationType: ActionType
|
||||
folderId: string
|
||||
|
||||
|
||||
|
||||
constructor(
|
||||
private publications: PublicationsService,
|
||||
private toastService: ToastService,
|
||||
private httpErroHandle: HttpErrorHandle,
|
||||
public PublicationFolderService: PublicationFolderService,
|
||||
private CMAPIService: CMAPIService,
|
||||
public publicationFolderService: PublicationFolderService,
|
||||
private platform: Platform,
|
||||
private modalController: ModalController,
|
||||
private router: Router,
|
||||
) {}
|
||||
|
||||
|
||||
clear() {
|
||||
|
||||
this.id = uuidv4()
|
||||
this.UploadFileUseCase = new UploadFileUseCase()
|
||||
this.form = new PublicationFormModel()
|
||||
@@ -65,7 +55,6 @@ export class PublicationFromMvService {
|
||||
window['upload-header-set-remove'](this.id)
|
||||
}
|
||||
|
||||
|
||||
setFolderId(folderId) {
|
||||
this.folderId = folderId
|
||||
}
|
||||
@@ -99,7 +88,6 @@ export class PublicationFromMvService {
|
||||
e.FileExtension = e.FileExtension || "mp4"
|
||||
e.Base64 = ''
|
||||
|
||||
|
||||
if(e.FileType == 'video' && !e.toUpload) {
|
||||
e.Base64 = e.url
|
||||
}
|
||||
@@ -142,7 +130,6 @@ export class PublicationFromMvService {
|
||||
window['publicationEdit']()
|
||||
}
|
||||
|
||||
// this.publicationFolderService.getPublicationsIds(this.folderId)
|
||||
window['upload-header-set-remove'](this.id);
|
||||
|
||||
} catch (error) {
|
||||
@@ -153,23 +140,16 @@ export class PublicationFromMvService {
|
||||
} else {
|
||||
window['upload-header-set-retry'](this.id)
|
||||
}
|
||||
} finally {
|
||||
// loader.remove()
|
||||
}
|
||||
|
||||
} finally {}
|
||||
|
||||
} else {
|
||||
this.toastService._badRequest("É necessário adicionar uma imagem ou vídeo")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else {
|
||||
let time = new Date()
|
||||
if (this.form.Files.length >= 1) {
|
||||
|
||||
// const loader = this.toastService.loading()
|
||||
|
||||
this.form.send = true
|
||||
const upload = await this.uploadVideosFiles()
|
||||
|
||||
@@ -180,8 +160,6 @@ export class PublicationFromMvService {
|
||||
window['upload-header-set-percentage'](this.id, 100)
|
||||
}
|
||||
|
||||
console.log('release chunk')
|
||||
|
||||
if(upload) {
|
||||
this.form.Files = this.form.Files.map((e:PublicationAttachmentEntity) => {
|
||||
if(e.FileType == 'video' && e.toUpload) {
|
||||
@@ -194,18 +172,14 @@ export class PublicationFromMvService {
|
||||
e.Base64 = e.url
|
||||
}
|
||||
|
||||
|
||||
return e
|
||||
})
|
||||
} else {
|
||||
window['upload-header-set-retry'](this.id)
|
||||
this.toastService._badRequest("ocorreu um erro ao enviar o ficheiro")
|
||||
return true
|
||||
// loader.remove()
|
||||
}
|
||||
|
||||
|
||||
|
||||
const publication: any = Object.assign({}, this.form)
|
||||
|
||||
publication.Files = publication.Files.map( (e:PublicationAttachmentEntity) => ({
|
||||
@@ -228,27 +202,18 @@ export class PublicationFromMvService {
|
||||
|
||||
this.httpErroHandle.httpsSucessMessagge('Criar publicação')
|
||||
|
||||
// this.goBackToViewPublications.emit();
|
||||
window['upload-header-set-remove'](this.id);
|
||||
this.doneUpload()
|
||||
this.publicationFolderService.loadPublication(publicationsId, this.folderId)
|
||||
} catch (error) {
|
||||
window['upload-header-set-retry'](this.id)
|
||||
this.httpErroHandle.httpStatusHandle(error)
|
||||
} finally {
|
||||
// loader.remove()
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
this.toastService._badRequest("É necessário adicionar uma imagem ou vídeo")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// this.PublicationHolderService.setPublication(this.publicationFormMV)
|
||||
|
||||
this.ObjectMergeNotification.close()
|
||||
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
<ion-header class="ion-no-border">
|
||||
<div *ngIf="publication.title != ''" class="title-content d-flex pl-20 pt-25">
|
||||
<div *ngIf="publication != null " class="title-content d-flex pl-20 pt-25">
|
||||
<div class="back-icon cursor-pointer" (click)="goBack()">
|
||||
<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>
|
||||
@@ -10,7 +10,7 @@
|
||||
<p class="post-data">{{publication.datePublication | date: 'dd-MM-yyyy | h:mm'}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="publication.title == ''" class="title-contentd-flex pl-20 pt-25">
|
||||
<div *ngIf="publication != null" class="title-contentd-flex pl-20 pt-25">
|
||||
<div class="back-icon cursor-pointer">
|
||||
<ion-icon (click)="goBack()" slot="end" src='assets/images/assets/images/theme/gov/icons-calendar-arrow-left.svg'></ion-icon>
|
||||
</div>
|
||||
@@ -24,7 +24,7 @@
|
||||
<ion-content>
|
||||
|
||||
<div class="content-container" #ScrollContainer>
|
||||
<div *ngIf="publication.title != ''">
|
||||
<div *ngIf="publication != null">
|
||||
<div class="post-item px-20">
|
||||
|
||||
<div style="width: 100%; height: 395px;overflow:hidden">
|
||||
|
||||
@@ -13,10 +13,8 @@ import { HttpErrorHandle } from 'src/app/services/http-error-handle.service';
|
||||
import { PublicationFolderService } from 'src/app/store/publication-folder.service';
|
||||
import { AskModalPage } from 'src/app/modals/ask-modal/ask-modal.page';
|
||||
import { checkFileTypeService } from 'src/app/services/checkFileType.service';
|
||||
import { PublicationVideoManagerService } from "src/app/services/publication/publication-video-manager.service";
|
||||
import { StopvideoService } from "src/app/services/stopvideo.service";
|
||||
import { PublicationHolderService } from 'src/app/services/publication/publication-holder.service'
|
||||
import { PublicationListByProcessIdService } from 'src/app/core/actions/use-case/publication-list-by-process-id.service'
|
||||
@Component({
|
||||
selector: 'app-view-publications',
|
||||
templateUrl: './view-publications.page.html',
|
||||
@@ -71,10 +69,8 @@ export class ViewPublicationsPage implements OnInit {
|
||||
private httpErrorHandle: HttpErrorHandle,
|
||||
public publicationFolderService: PublicationFolderService,
|
||||
public checkFileType: checkFileTypeService,
|
||||
private publicationVideoManagerService: PublicationVideoManagerService,
|
||||
public StopvideoService: StopvideoService,
|
||||
public PublicationHolderService: PublicationHolderService,
|
||||
private publicationListByProcessIdService: PublicationListByProcessIdService
|
||||
public PublicationHolderService: PublicationHolderService
|
||||
) {
|
||||
this.createPublicationList()
|
||||
}
|
||||
@@ -116,11 +112,6 @@ export class ViewPublicationsPage implements OnInit {
|
||||
this.getPublicationDetail();
|
||||
this.getPublicationsIds();
|
||||
this.stopVideo();
|
||||
|
||||
setTimeout(() => {
|
||||
this.doRefresh({})
|
||||
}, 1500);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -136,6 +127,7 @@ export class ViewPublicationsPage implements OnInit {
|
||||
|
||||
doRefresh = (event) => {
|
||||
|
||||
this.publicationFolderService.loadPublications(this.folderId);
|
||||
this.getPublicationDetail();
|
||||
this.getPublicationsIds();
|
||||
}
|
||||
|
||||
@@ -7,32 +7,33 @@
|
||||
[src]="'data:image/jpg;base64,' + files.file" loading="lazy">
|
||||
|
||||
|
||||
<video #videoElements [appVisibility]="onVisibilityChange" *ngIf="checkFileType.checkFileType(files.extension ) == 'video'" class="post-video" controls="controls" preload="none"
|
||||
playsinline webkit-playsinline="webkit-playsinline" (play)="stopvideoService.registerVideoWithEvent($event)"q>
|
||||
<source
|
||||
*ngIf="files.extension === 'MP4'"
|
||||
[src]="'data:video/mp4;base64,' + files.file"
|
||||
type="video/mp4"
|
||||
>
|
||||
<source
|
||||
*ngIf="files.extension === 'MOV'"
|
||||
[src]="'data:video/quicktime;base64,' + files.file"
|
||||
type="video/quicktime"
|
||||
>
|
||||
<video
|
||||
#videoElements
|
||||
[appVisibility]="onVisibilityChange"
|
||||
*ngIf="checkFileType.checkFileType(files.extension) == 'video'"
|
||||
class="post-video"
|
||||
controls
|
||||
preload="metadata"
|
||||
playsinline
|
||||
webkit-playsinline
|
||||
(loadeddata)="videoElements.currentTime = 0.1"
|
||||
(play)="stopvideoService.registerVideoWithEvent($event)"
|
||||
>
|
||||
<source
|
||||
*ngIf="files.extension === 'mp4'"
|
||||
[src]="'data:video/mp4;base64,' + files.file"
|
||||
type="video/mp4"
|
||||
>
|
||||
<source
|
||||
*ngIf="files.extension === 'MOV'"
|
||||
[src]="'data:video/quicktime;base64,' + files.file"
|
||||
type="video/quicktime"
|
||||
>
|
||||
</video>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
</swiper-slide>
|
||||
</swiper-container>
|
||||
</div>
|
||||
|
||||
<ion-footer>
|
||||
<div *ngIf="pagination && publicationList?.length > 1" class="dots-container">
|
||||
<span *ngFor="let files of publicationList; let k = index"
|
||||
[class.dotsSwiper]="true"
|
||||
[class.active-dot]="swiperIndex === k"
|
||||
(click)="goToSlide(k)"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</ion-footer>
|
||||
|
||||
@@ -64,8 +64,21 @@ export class SwiperPage implements OnInit {
|
||||
}
|
||||
} else if(e.isOk()) {
|
||||
this.publicationList = e.value;
|
||||
|
||||
var a = e.value.find(e => e.datePublication != this.datePublication)
|
||||
if(a) {
|
||||
var result = await this.publicationFileGetByDocumentIdService.execute({
|
||||
documentId: this.documentId,
|
||||
processId: this.processId,
|
||||
datePublication: this.datePublication
|
||||
});
|
||||
|
||||
if(result.isOk()) {
|
||||
this.publicationList = result.value.added;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
|
||||
@@ -41,41 +41,49 @@ export class PublicationFolderService {
|
||||
|
||||
async loadPublications(processId: number) {
|
||||
|
||||
var id = processId+0
|
||||
|
||||
this.showLoader = true;
|
||||
|
||||
if (!this.publications[processId]) {
|
||||
this.publications[processId] = []
|
||||
if (!this.publications[id]) {
|
||||
this.publications[id] = []
|
||||
|
||||
const result = await this.publicationLocalRepo.find({processId});
|
||||
const result = await this.publicationLocalRepo.find({processId: id});
|
||||
|
||||
if(result.isOk()) {
|
||||
this.publications[processId] = result.value;
|
||||
this.publications[id] = result.value;
|
||||
}
|
||||
}
|
||||
|
||||
const result = await this.publicationListByProcessIdService.execute(processId);
|
||||
const result = await this.publicationListByProcessIdService.execute(id);
|
||||
|
||||
if(result.isOk()) {
|
||||
for(const item of result.value.added) {
|
||||
this.publications[processId].push(item);
|
||||
this.publications[id].push(item);
|
||||
}
|
||||
|
||||
// handle removed
|
||||
for (const item of result.value.remove) {
|
||||
this.publications[processId] = this.publications[processId].filter(f => f.documentId !== item.documentId);
|
||||
this.publications[id] = this.publications[id].filter(f => f.documentId !== item.documentId);
|
||||
}
|
||||
|
||||
// handle updated
|
||||
for (const item of result.value.updated) {
|
||||
const index = this.publications[processId].findIndex(f => f.documentId === item.documentId);
|
||||
const index = this.publications[id].findIndex(f => f.documentId === item.documentId);
|
||||
if (index !== -1) {
|
||||
this.publications[processId][index] = item; // replace with updated version
|
||||
this.publications[id][index] = item; // replace with updated version
|
||||
} else {
|
||||
this.publications[processId].push(item); // if not found, just add it
|
||||
this.publications[id].push(item); // if not found, just add it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.publications[id] = this.publications[id].sort((a, b) => {
|
||||
const dateA = new Date(a.datePublication).getTime();
|
||||
const dateB = new Date(b.datePublication).getTime();
|
||||
return dateB - dateA; // Revertendo a ordem aqui
|
||||
});
|
||||
|
||||
this.showLoader = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,7 @@ import { isHttpError } from 'src/app/services/http.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { NotificationRepositoryService } from 'src/app/module/notification/data/notification-repository.service';
|
||||
import { EEventFilterStatus } from 'src/app/module/agenda/data/dto/enums';
|
||||
// import { Unsubscribable } from '../../../../android/app/build/intermediates/assets/debug/public/assets/dexie/dist/dexie';
|
||||
|
||||
import { ProcessesService } from 'src/app/services/processes.service'
|
||||
@Component({
|
||||
selector: 'app-agenda',
|
||||
templateUrl: './agenda.page.html',
|
||||
@@ -204,7 +203,7 @@ export class AgendaPage implements OnInit {
|
||||
public RoleIdService: RoleIdService,
|
||||
public AgendaDataRepositoryService: AgendaDataRepositoryService,
|
||||
private toastService: ToastService,
|
||||
private notificationRepository: NotificationRepositoryService
|
||||
private notificationRepository: NotificationRepositoryService,
|
||||
) {
|
||||
|
||||
this.NotificationUpdate.pipe(
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<!-- {{ expirationDate[room.$id] !== null ? expirationDate[room.$id] + ' seconds left' : 'No expiration' }} -->
|
||||
<span *ngIf="expirationDate[room.$id]"> {{ expirationDate[room.$id] !== null ? expirationDate[room.$id] + ' seconds left' : '' }} </span>
|
||||
</div>
|
||||
<div *ngIf="room?.messages?.length >= 1 && room.messages[0].isDeleted!=true" class="item-description d-flex align-items-center" [class.item-description-active]="room.$id ==selectedRoomId">
|
||||
<div *ngIf="room?.messages?.length >= 1 && room.messages[0]._isDeleted!=true" class="item-description d-flex align-items-center" [class.item-description-active]="room.$id ==selectedRoomId">
|
||||
<!-- -->
|
||||
<!-- <div *ngIf="room?.messages?.[0]?.message" class="item-description d-flex align-items-center" [class.item-description-active]="room.$id ==selectedRoomId"> -->
|
||||
<!-- <div class="item-message" *ngIf="group.otherUserType == false">{{room?.messages?.[0]?.message.u.name}}: {{room?.messages?.[0]?.message.msg}} </div> -->
|
||||
@@ -94,7 +94,6 @@
|
||||
<!-- <div *ngIf="group.otherUserType == true">{{group.userThatIsTyping}} está escrever ...</div> -->
|
||||
|
||||
<div class="item-files add-ellipsis" *ngIf="room.messages[0]?.attachments?.length >= 1">
|
||||
|
||||
<fa-icon *ngIf="room.lastMessageDocument" icon="file-alt" class="file-icon" [class.set-active-item-font-to-white]="room.$id == selectedRoomId"></fa-icon>
|
||||
<fa-icon *ngIf="room.lastMessageAudio" icon="file-audio" class="file-icon" [class.set-active-item-font-to-white]="room.$id == selectedRoomId"></fa-icon>
|
||||
<span *ngIf="room.lastMessageAudio" class="item-files-title font-13-em"> audio </span>
|
||||
@@ -103,20 +102,14 @@
|
||||
<span class="pl-2 font-13-em add-ellipsis" *ngIf="!room.lastMessageAudio && !room.lastMessageImage">{{ room.messages[0].attachments[0].description }}</span>
|
||||
</div>
|
||||
|
||||
<!-- <div class="item-files" *ngIf="room.attachments">
|
||||
<div *ngIf="room.value.lastMessage.attachments[0].image_url">
|
||||
<fa-icon icon="image" class="file-icon" [class.set-active-item-font-to-white]="room.$id == selectedRoomId"></fa-icon>
|
||||
<span> Fotografia</span>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div *ngIf="room?.messages?.length >= 1 && room.messages[0].isDeleted==true">
|
||||
<div *ngIf="room?.messages?.length >= 1 && room.messages[0]._isDeleted==true && room.messages[0].oneShot == false">
|
||||
<div class="item-message font-13-em add-ellipsis white-space-nowrap"> Mensagem foi eliminada </div>
|
||||
</div>
|
||||
<!-- -->
|
||||
<div *ngIf="room?.messages?.length >= 1 && room.messages[0]._isDeleted==true && room.messages[0].oneShot == true">
|
||||
<div class="item-message font-13-em add-ellipsis white-space-nowrap"> Mensagem de visualizada </div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="item-message font-13-em add-ellipsis white-space-nowrap" *ngIf="room.otherUserType == false"> {{room.messages[0].message}} </div> -->
|
||||
<!-- <div class="font-13-em" *ngIf="room.otherUserType == true">está escrever ...</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -27,6 +27,7 @@ import { MessageLocalDataSourceService } from 'src/app/module/chat/data/reposito
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { Logger } from 'src/app/services/logger/main/service';
|
||||
import { IDBoolean } from 'src/app/infra/database/dexie/type';
|
||||
import { MessageViewModal } from './store/model/message';
|
||||
@Component({
|
||||
selector: 'app-chat',
|
||||
templateUrl: './chat.page.html',
|
||||
@@ -156,7 +157,12 @@ export class ChatPage implements OnInit {
|
||||
// ]);
|
||||
|
||||
this.roomLocalDataSourceService.getItemsLive().pipe(
|
||||
map((roomList) => roomList.map((room)=> new RoomViewModel(room))),
|
||||
map((roomList) => roomList.map((room)=> {
|
||||
room.messages = room.messages.map( e => {
|
||||
return new MessageViewModal(e);
|
||||
});
|
||||
return new RoomViewModel(room);
|
||||
})),
|
||||
tap((roomList) => {
|
||||
this.updatemessage(roomList)
|
||||
})
|
||||
|
||||
@@ -10,6 +10,8 @@ import { ZodError } from 'zod';
|
||||
|
||||
import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service';
|
||||
import { IRoomLocalRepository } from 'src/app/core/chat/repository/room/room-local-repository';
|
||||
import { GetRoomListUseCaseService } from 'src/app/core/chat/usecase/room/room-get-list-use-case.service';
|
||||
import { GetRoomByIdUseCaseService } from 'src/app/core/chat/usecase/room/room-get-by-id-use-case.service';
|
||||
|
||||
|
||||
@Component({
|
||||
@@ -39,6 +41,8 @@ export class EditGroupPage implements OnInit {
|
||||
private toastService: ToastService,
|
||||
private chatServiceService: ChatServiceService,
|
||||
private RoomLocalDataSourceService: IRoomLocalRepository,
|
||||
private GetRoomListUseCaseService: GetRoomListUseCaseService,
|
||||
private getRoomByIdUseCaseService: GetRoomByIdUseCaseService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -75,6 +79,9 @@ export class EditGroupPage implements OnInit {
|
||||
roomType: 0
|
||||
})
|
||||
|
||||
this.GetRoomListUseCaseService.execute();
|
||||
//this.getRoomByIdUseCaseService.execute(this.roomId);
|
||||
|
||||
if(result.isOk()) {
|
||||
this.openGroupMessage.emit(this.roomId);
|
||||
} else if (result.error instanceof HttpResponse) {
|
||||
@@ -84,7 +91,6 @@ export class EditGroupPage implements OnInit {
|
||||
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
|
||||
|
||||
@@ -152,16 +152,21 @@
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="message-container rotate-div" *ngIf="message.isDeleted == true">
|
||||
<div class="message-container rotate-div" *ngIf="message._isDeleted == true && message.id != '' && message.oneShot == false">
|
||||
Mensagem foi eliminada
|
||||
</div>
|
||||
|
||||
<div class="message-container rotate-div" *ngIf="message._isDeleted == true && message.id != '' && message.oneShot == true">
|
||||
Mensagem de visualizada
|
||||
</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>
|
||||
<div class="rotate-div emoji-container" *ngIf="message.isDeleted != true && message.messageType != IMessageType.information && message.ballon != true">
|
||||
<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>
|
||||
@@ -232,7 +237,7 @@
|
||||
|
||||
<div class="width-100">
|
||||
<div *ngIf="!recording && !lastAudioRecorded" class="type-message">
|
||||
<ion-textarea *ngIf="allowTyping" (keyup.enter)="sendMessage()" clearOnEdit="true" placeholder="Escrever uma mensagem" class="message-input" rows="1" [(ngModel)]="textField" (ionChange)="sendTyping()" (click)="sendReadAt()"></ion-textarea>
|
||||
<ion-textarea *ngIf="allowTyping" (keyup.enter)="sendMessage()" clearOnEdit="true" placeholder="Escrever uma mensagem" 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">
|
||||
|
||||
@@ -194,9 +194,11 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
this.roomData$ = this.RoomLocalRepository.getRoomByIdLive(this.room.$id)
|
||||
|
||||
this.roomData$.subscribe(e => {
|
||||
if(e) {
|
||||
if(e && this.room.$id == e?.$id) {
|
||||
this.room = new RoomViewModel(e)
|
||||
this.roomType = e.roomType;
|
||||
} else {
|
||||
console.log(e);
|
||||
}
|
||||
})
|
||||
|
||||
@@ -433,6 +435,12 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
modal.present()
|
||||
|
||||
return modal.onDidDismiss().then((res) => {
|
||||
this.chatServiceService.sendReadAt({
|
||||
memberId: SessionStore.user.UserId,
|
||||
messageId: message.id,
|
||||
requestId: '',
|
||||
roomId: this.room.id
|
||||
})
|
||||
this.messageDelete(message)
|
||||
});
|
||||
}
|
||||
@@ -446,21 +454,19 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
const me = message.haveSeen(message.info)
|
||||
|
||||
if(!me) {
|
||||
// Logger.info('send read at, sender '+ message.sender.wxFullName+ ' '+ message.message +'message id'+ message.id)
|
||||
|
||||
this.chatServiceService.sendReadAt({
|
||||
memberId: SessionStore.user.UserId,
|
||||
messageId: message.id,
|
||||
requestId: uuidv4(),
|
||||
roomId: this.room.id
|
||||
})
|
||||
} else {
|
||||
// console.log('no need', message )
|
||||
if(message.oneShot == false) {
|
||||
this.chatServiceService.sendReadAt({
|
||||
memberId: SessionStore.user.UserId,
|
||||
messageId: message.id,
|
||||
requestId: uuidv4(),
|
||||
roomId: this.room.id
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('dont read for this room')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,12 +501,14 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
}
|
||||
}
|
||||
|
||||
this.chatServiceService.sendReadAt({
|
||||
memberId: SessionStore.user.UserId,
|
||||
messageId: message.id,
|
||||
requestId: '',
|
||||
roomId: this.room.id
|
||||
})
|
||||
if(message.oneShot == false) {
|
||||
this.chatServiceService.sendReadAt({
|
||||
memberId: SessionStore.user.UserId,
|
||||
messageId: message.id,
|
||||
requestId: '',
|
||||
roomId: this.room.id
|
||||
})
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
this.scrollToBottomClicked()
|
||||
@@ -612,12 +620,6 @@ export class MessagesPage implements OnInit, OnChanges, AfterViewInit, OnDestroy
|
||||
}
|
||||
|
||||
|
||||
sendReadAt() {
|
||||
// this.chatServiceService.messageMarkAsRead({roomId: this.room.$id}).then((e) => {
|
||||
// console.log(e)
|
||||
// })
|
||||
}
|
||||
|
||||
sendTyping() {
|
||||
if(this.room.local == IDBoolean.false) {
|
||||
this.UserTypingRemoteRepositoryService.sendTyping(this.room.id)
|
||||
|
||||
@@ -8,6 +8,9 @@ import { HttpErrorHandle } from 'src/app/services/http-error-handle.service';
|
||||
import { ThemeService } from 'src/app/services/theme.service'
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { ZodError } from 'zod';
|
||||
import { GetRoomListUseCaseService } from 'src/app/core/chat/usecase/room/room-get-list-use-case.service';
|
||||
import { GetRoomByIdUseCaseService } from 'src/app/core/chat/usecase/room/room-get-by-id-use-case.service';
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-group',
|
||||
@@ -31,6 +34,8 @@ export class EditGroupPage implements OnInit {
|
||||
private toastService: ToastService,
|
||||
private chatServiceService: ChatServiceService,
|
||||
private RoomLocalDataSourceService: IRoomLocalRepository,
|
||||
private GetRoomListUseCaseService: GetRoomListUseCaseService,
|
||||
private getRoomByIdUseCaseService: GetRoomByIdUseCaseService
|
||||
) {
|
||||
this.roomId = this.navParams.get('roomId');
|
||||
}
|
||||
@@ -67,6 +72,10 @@ export class EditGroupPage implements OnInit {
|
||||
roomType: 0
|
||||
})
|
||||
|
||||
|
||||
this.GetRoomListUseCaseService.execute();
|
||||
//this.getRoomByIdUseCaseService.execute(this.roomId);
|
||||
|
||||
if(result.isOk()) {
|
||||
this.modalController.dismiss();
|
||||
} else if (result.error instanceof HttpResponse) {
|
||||
|
||||
@@ -38,6 +38,7 @@ import { RoomStore } from '../../store/roomStore'
|
||||
import { EditGroupPage } from '../edit-group/edit-group.page';
|
||||
import { imageMimeTypes } from 'src/app/utils/allowedImageExtension';
|
||||
import { GroupContactsPage, IGroupContactsPageOutPutSchema } from '../group-contacts/group-contacts.page';
|
||||
import { ChatServiceService } from 'src/app/module/chat/domain/chat-service.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-messages',
|
||||
@@ -121,6 +122,7 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
|
||||
private file: File,
|
||||
private fileSystemMobileService: FileSystemMobileService,
|
||||
public RoomStore: RoomStore,
|
||||
private chatServiceService: ChatServiceService,
|
||||
) {
|
||||
|
||||
this.room = this.navParams.get('room');
|
||||
@@ -750,6 +752,12 @@ export class MessagesPage implements OnInit, AfterViewInit, OnDestroy {
|
||||
modal.present()
|
||||
|
||||
return modal.onDidDismiss().then((res) => {
|
||||
this.chatServiceService.sendReadAt({
|
||||
memberId: SessionStore.user.UserId,
|
||||
messageId: message.id,
|
||||
requestId: '',
|
||||
roomId: this.room.id
|
||||
})
|
||||
this.messageDelete(message)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -65,10 +65,10 @@ export class MessageViewModal {
|
||||
}
|
||||
this.setMessageUIType()
|
||||
|
||||
if(this.isDeleted != true && this.messageType != IMessageType.information) {
|
||||
if(this._isDeleted == false && this.messageType != IMessageType.information) {
|
||||
this.showReaction = true
|
||||
}
|
||||
if(this.isDeleted == false && this.messageType == IMessageType.normal) {
|
||||
if(this._isDeleted == false && this.messageType == IMessageType.normal) {
|
||||
this.showMessage = true
|
||||
}
|
||||
|
||||
@@ -118,4 +118,8 @@ export class MessageViewModal {
|
||||
meSender() {
|
||||
return this.sender.wxUserId == SessionStore.user.UserId
|
||||
}
|
||||
|
||||
get _isDeleted() {
|
||||
return this.isDeleted || this.info.filter(e =>e.memberId == SessionStore.user.UserId && e.isDeleted).length == 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { IRoom, RoomEntitySchema } from "src/app/core/chat/entity/group";
|
||||
import { MessageAttachmentSource } from "src/app/core/chat/entity/message";
|
||||
import { isDocument } from "src/app/utils/document-mimetype";
|
||||
import { MessageViewModal } from "./message";
|
||||
|
||||
export class RoomViewModel implements IRoom {
|
||||
|
||||
@@ -12,7 +13,7 @@ export class RoomViewModel implements IRoom {
|
||||
expirationDate: typeof RoomEntitySchema._input.expirationDate
|
||||
roomType: typeof RoomEntitySchema._input.roomType
|
||||
members: typeof RoomEntitySchema._input.members
|
||||
messages: typeof RoomEntitySchema._input.messages
|
||||
messages: MessageViewModal[]
|
||||
local: typeof RoomEntitySchema._input.local
|
||||
receiverId?: typeof RoomEntitySchema._input.receiverId
|
||||
displayDate = ''
|
||||
|
||||
@@ -224,12 +224,15 @@ export class RoomStore {
|
||||
}
|
||||
}
|
||||
|
||||
this.chatServiceService.sendReadAt({
|
||||
memberId: SessionStore.user.UserId,
|
||||
messageId: message.id,
|
||||
requestId: uuidv4(),
|
||||
roomId: this.room.id
|
||||
})
|
||||
if(message.oneShot == false) {
|
||||
this.chatServiceService.sendReadAt({
|
||||
memberId: SessionStore.user.UserId,
|
||||
messageId: message.id,
|
||||
requestId: uuidv4(),
|
||||
roomId: this.room.id
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
this.scrollToBottomClicked()
|
||||
@@ -348,12 +351,15 @@ export class RoomStore {
|
||||
if(!me) {
|
||||
// Logger.info('send read at, sender '+ message.sender.wxFullName+ ' '+ message.message +'message id'+ message.id)
|
||||
|
||||
this.chatServiceService.sendReadAt({
|
||||
memberId: SessionStore.user.UserId,
|
||||
messageId: message.id,
|
||||
requestId: uuidv4(),
|
||||
roomId: this.room.id
|
||||
})
|
||||
if(message.oneShot == false) {
|
||||
this.chatServiceService.sendReadAt({
|
||||
memberId: SessionStore.user.UserId,
|
||||
messageId: message.id,
|
||||
requestId: uuidv4(),
|
||||
roomId: this.room.id
|
||||
})
|
||||
}
|
||||
|
||||
} else {
|
||||
// console.log('no need', message )
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
<div class="main-tab pb-10 ion-toolbar header-color">
|
||||
|
||||
<div class="mobile pt-20 d-flex div-top-header justify-space-between">
|
||||
|
||||
<div title="Pesquisa" *ngIf="!hideSearchBtn" class="div-search viewport-font-size">
|
||||
<div (click)="openSearch()" class="{{Cy.header.b.search}}">
|
||||
<ion-icon *ngIf="ThemeService.currentTheme == 'doneIt' " class="font-45-em"
|
||||
@@ -54,7 +53,7 @@
|
||||
|
||||
|
||||
<div (click)="openProfile()" *ngIf="(profilePictureSubject | async) as calendarData" class="profile-image">
|
||||
<img *ngIf="calendarData.base64 != null" class="profile-image image-prety" src={{calendarData.base64}}>
|
||||
<img *ngIf="calendarData.base64 != null" class="profile-image image-prety" [src]="getSafeImage(calendarData.base64)">
|
||||
<ion-icon *ngIf="calendarData.base64 == null"
|
||||
class="icon font-45-em" src='assets/images/theme/gov/icons-profile.svg'></ion-icon>
|
||||
</div>
|
||||
@@ -189,7 +188,7 @@
|
||||
|
||||
<div title="Perfil" class="div-profile d-flex cursor-pointer font-45-rem" (click)="openProfile()">
|
||||
<div *ngIf="(profilePictureSubject | async) as calendarData" class="profile-image d-flex">
|
||||
<img *ngIf="calendarData.base64 != null" class="profile-image image-prety" src={{calendarData.base64}}>
|
||||
<img *ngIf="calendarData.base64 != null" class="profile-image image-prety" [src]="getSafeImage(calendarData.base64)">
|
||||
<ion-icon *ngIf="calendarData.base64 == null"
|
||||
class="icon font-45-rem image-prety" src='assets/images/theme/gov/icons-profile.svg'></ion-icon>
|
||||
</div>
|
||||
|
||||
@@ -23,6 +23,7 @@ import { UserRepositoryService } from 'src/app/module/user/data/user-repository.
|
||||
import { UserProfilePicture } from 'src/app/module/user/data/datasource/user-local-repository.service';
|
||||
import { TracingType, XTracerAsync } from 'src/app/services/monitoring/opentelemetry/tracer';
|
||||
import { isHttpError } from 'src/app/services/http.service';
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
selector: 'app-header',
|
||||
@@ -80,7 +81,8 @@ export class HeaderPage implements OnInit {
|
||||
public HeaderSettingsService: HeaderSettingsService,
|
||||
public PublicationHolderService: PublicationHolderService,
|
||||
private notificationRepositoryService: NotificationRepositoryService,
|
||||
private UserRepositoryService: UserRepositoryService
|
||||
private UserRepositoryService: UserRepositoryService,
|
||||
private sanitizer: DomSanitizer
|
||||
) {
|
||||
this.profilePictureSubject = this.UserRepositoryService.getProfilePictureLive() as any
|
||||
this.notificationCount$ = this.notificationRepositoryService.getNotificationLiveCount()
|
||||
@@ -106,6 +108,10 @@ export class HeaderPage implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
getSafeImage(base64: string) {
|
||||
return this.sanitizer.bypassSecurityTrustUrl(base64);
|
||||
}
|
||||
|
||||
updateCount = () => {
|
||||
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ import { environment as oaprProd } from './suport/oapr'
|
||||
// import { environment as doneITProd } from './suport/doneIt'
|
||||
|
||||
|
||||
export const environment: Environment = DevDev;
|
||||
export const environment: Environment = oaprProd;
|
||||
|
||||
File diff suppressed because one or more lines are too long
+2
-2
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
|
||||
|
||||
<!-- Add MIME type for APK -->
|
||||
<staticContent>
|
||||
<mimeMap fileExtension=".apk" mimeType="application/vnd.android.package-archive" />
|
||||
@@ -23,7 +23,7 @@
|
||||
<httpProtocol>
|
||||
<customHeaders>
|
||||
<!-- Iframe on the same host only -->
|
||||
<add name="Content-Security-Policy" value="frame-ancestors https://gdviewer-dev.dyndns.info/" />
|
||||
<add name="Content-Security-Policy" value="frame-ancestors https://gdqas-api.oapr.gov.ao/" />
|
||||
<!-- HTTPS on -->
|
||||
<add name="Strict-Transport-Security" value="max-age=31536000" />
|
||||
<add name="Referrer-Policy" value="no-referrer" />
|
||||
|
||||
Reference in New Issue
Block a user