vue-wiguet-chatweb 0.1.24 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue-wiguet-chatweb",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -34,11 +34,9 @@
34
34
  "prepack": "npm run build"
35
35
  },
36
36
  "peerDependencies": {
37
- "@primevue/themes": "^4.2.5",
38
37
  "@vueuse/core": "^10.0.0",
39
38
  "axios": "^1.4.0",
40
39
  "luxon": "^3.0.0",
41
- "primevue": "^4.2.5",
42
40
  "socket.io-client": "^4.7.2",
43
41
  "uuid": "^9.0.1",
44
42
  "vue": "^3.2.0"
@@ -47,9 +45,11 @@
47
45
  "@vueuse/core": "^10.0.0",
48
46
  "axios": "^1.4.0",
49
47
  "luxon": "^3.0.0",
48
+ "socket.io-client": "^4.7.2",
50
49
  "uuid": "^9.0.1"
51
50
  },
52
51
  "devDependencies": {
52
+ "@primevue/auto-import-resolver": "^4.2.5",
53
53
  "@types/luxon": "^3.4.2",
54
54
  "@types/node": "^20.4.6",
55
55
  "@types/uuid": "^10.0.0",
@@ -17,6 +17,12 @@
17
17
  @loadMore="getMessages"
18
18
  @retry="retryMessage"
19
19
  @on-qualifying="(args) => onQualifying(args)"
20
+ @see="(message: Message) => {
21
+ currentDialogView = DIALOG_VIEWS.SEE
22
+ urlFileMessage = message.urlFile
23
+ dialog.title = 'Imagen'
24
+ dialog.modelValue = true
25
+ }"
20
26
  />
21
27
  <div class="fit" v-else>
22
28
  <span class="center">No tienes mensajes</span>
@@ -42,28 +48,29 @@
42
48
  @keyup.enter="saltoDeLineaOEnviar"
43
49
  />
44
50
 
45
- <FileUpload
46
- mode="basic"
47
- accept="image/png,image/jpeg,image/jpg,image/webp"
48
- :maxFileSize="2000000"
49
- @select="onFileSelect"
50
- title="Adjuntar imagen"
51
- :chooseButtonProps="{ label: '', outlined: true }"
52
- :auto="false"
53
- style="height: 39px"
51
+ <input
52
+ type="file"
53
+ ref="fileInputRef"
54
+ @change="onFileSelect"
55
+ accept="image/*"
56
+ style="display: none;"
57
+ key="fileInputKey"
58
+
59
+ />
60
+ <button
61
+ type="button"
62
+ class="pointer btn-primary"
63
+ title="Adjuntar archivo"
64
+ @click="
65
+ () => {
66
+ fileInputRef.value = '';
67
+ fileInputKey++;
68
+ fileInputRef?.click();
69
+ }
70
+ "
54
71
  >
55
- <template #filelabel>
56
- <span style="display:none"></span>
57
- </template>
58
-
59
- <template #chooseicon>
60
- <IconAttach style="width: 20px; height: 20px" />
61
- </template>
62
- </FileUpload>
63
-
64
- <!-- <button class="pointer btn-primary">
65
72
  <IconAttach style="width: 20px; height: 20px" />
66
- </button> -->
73
+ </button>
67
74
 
68
75
  <button type="submit" class="pointer btn-primary">
69
76
  <IconSend style="width: 20px; height: 20px" />
@@ -77,12 +84,11 @@
77
84
  </div>
78
85
  </div>
79
86
 
80
- <ODialog v-bind="dialog" modal>
81
- <div class="flex flex-col gap-3 justify-center items-center">
82
- <Image v-for="(urlFile, i) in urlFiles" :key="i" :src="urlFile" alt="Image" width="400" />
87
+ <ODialog v-bind="dialog">
88
+ <div v-if="currentDialogView === DIALOG_VIEWS.UPLOAD" class="flex flex-col gap-3 justify-center items-center">
89
+ <img v-for="(urlFile, i) in urlFiles" :key="i" :src="urlFile.toString()" alt="Image" width="400" />
83
90
 
84
- <div class="w-full">
85
- <form
91
+ <form
86
92
  class="message-send"
87
93
  @submit.prevent="
88
94
  (event) => {
@@ -116,8 +122,10 @@
116
122
  </button>
117
123
  </div>
118
124
  </div>
119
- </form>
120
- </div>
125
+ </form>
126
+ </div>
127
+ <div v-else>
128
+ <img v-if="urlFileMessage" :src="urlFileMessage" alt="Image" style="width: 55vw;" />
121
129
  </div>
122
130
  </ODialog>
123
131
  </template>
@@ -156,16 +164,22 @@ import { io, Socket } from "socket.io-client";
156
164
  import { APP_TYPE } from "../dto/chat.dto";
157
165
  import { MESSAGE_TYPE_CODES, TypeMessageTypeCodes } from "../resources/constants/message-type.constant";
158
166
  import { useMobile } from "../hooks/useMobile";
159
- import { IPropsDialog } from "./ODialog/IPropsDialog";
160
167
  import IconAttach from "./IconAttach.vue";
161
168
  import ODialog from "./ODialog/ODialog.vue";
162
- import { type FileUploadSelectEvent } from "primevue";
163
- import FileUpload from "primevue/fileupload";
164
- import Image from "primevue/image";
169
+ import { IPropsDialog } from "./ODialog/IPropsDialog";
170
+
171
+ const enum DIALOG_VIEWS {
172
+ UPLOAD,
173
+ SEE
174
+ }
165
175
 
166
176
  //DATA
167
177
  const message = ref("");
168
178
  const notViewed = ref(0);
179
+ const fileInputRef = ref();
180
+ const fileInputKey = ref(0);
181
+ const currentDialogView = ref(DIALOG_VIEWS.SEE)
182
+ const urlFileMessage = ref<string>()
169
183
 
170
184
  const messagesData = ref<{ data: Message[]; canLoadMoreMessages: boolean }>({
171
185
  data: [],
@@ -267,10 +281,7 @@ function createMessage(message: string, codigoTipoMensaje?: TypeMessageTypeCodes
267
281
  ? {
268
282
  code: codigoTipoMensaje,
269
283
  }
270
- : undefined;
271
-
272
- console.warn(inputFiles.value);
273
-
284
+ : undefined;
274
285
 
275
286
  const newMessage: Message = {
276
287
  id: uuidv4(),
@@ -283,7 +294,7 @@ function createMessage(message: string, codigoTipoMensaje?: TypeMessageTypeCodes
283
294
  createdAt: new Date().toISOString(),
284
295
  updatedAt: new Date().toISOString(),
285
296
  file: inputFiles.value?.[0],
286
- urlFile: inputFiles.value?.[0]?.objectURL,
297
+ urlFile: urlFiles.value?.[0].toString(),
287
298
  messageType,
288
299
  sender: {
289
300
  nombreCompleto: props.user.nombreCompleto,
@@ -570,29 +581,29 @@ function onQualifying({ message: messageParam, emoji }: { message: Message, emoj
570
581
  const isDisabledBoxMessage = ref(false);
571
582
 
572
583
  // Adjuntar
573
- function onFileSelect(event: FileUploadSelectEvent) {
584
+ function onFileSelect() {
574
585
  inputFiles.value = [];
575
586
  urlFiles.value = [];
576
587
 
577
- const file = event.files[0]; // Obtiene el primer archivo seleccionado
588
+ const filesParam = fileInputRef.value?.files ?? []
589
+
590
+ const file = filesParam?.[0];
578
591
 
579
- inputFiles.value = event.files as (File & { objectURL: string })[];
592
+ inputFiles.value = filesParam;
580
593
 
581
594
  if (!file) return;
582
595
 
583
- const reader = new FileReader();
584
- reader.onload = (e) => {
585
- e.target?.result && urlFiles.value.push(e.target?.result);
586
- };
587
- reader.readAsDataURL(file);
596
+ urlFiles.value.push(URL.createObjectURL(file))
588
597
 
598
+ currentDialogView.value = DIALOG_VIEWS.UPLOAD;
599
+ dialog.title = 'Preparar imagen';
589
600
  dialog.modelValue = true;
590
601
  }
591
602
 
592
603
  // Dialog
593
604
 
594
605
  const inputFiles = ref<(File & { objectURL: string })[]>([]);
595
- const urlFiles = ref<Array<string | ArrayBuffer>>([]);
606
+ const urlFiles = ref<Array<string>>([]);
596
607
 
597
608
  const dialog = reactive<IPropsDialog>({
598
609
  modelValue: false,
@@ -604,8 +615,7 @@ const dialog = reactive<IPropsDialog>({
604
615
  urlFiles.value = [];
605
616
  inputFiles.value = [];
606
617
  },
607
- hideActions: true,
608
- title: 'SIN TITULO',
618
+ title: 'Preparar imagen'
609
619
  });
610
620
 
611
621
  //
@@ -50,18 +50,10 @@
50
50
  </div>
51
51
 
52
52
  <div v-else>
53
- <div v-if="message.messageType?.code === MESSAGE_TYPE_CODES.IMAGEN" class="text-center">
54
- <Image
55
- alt="Image"
56
- preview
57
- >
58
- <template #image>
59
- <img :src="message.thumbnailFile ?? message.urlFile" alt="image" width="150" />
60
- </template>
61
- <template #original="slotProps">
62
- <img :src="message.urlFile" alt="preview" :style="slotProps.style" width="800" @click="slotProps.previewCallback" />
63
- </template>
64
- </Image>
53
+ <div v-if="message.messageType?.code === MESSAGE_TYPE_CODES.IMAGEN" style="text-align: center;">
54
+ <a href="javascript:" class="btn-icon" @click="emit('see', message)">
55
+ <img :src="message.thumbnailFile ?? message.urlFile" alt="image" width="150" />
56
+ </a>
65
57
  </div>
66
58
 
67
59
  <div v-if="emoji[message.message ?? '']">
@@ -108,9 +100,8 @@ import HappiestIcon from '../assets/emojis/HappiestIcon.svg'
108
100
  import NeutralIcon from '../assets/emojis/NeutralIcon.svg'
109
101
  import HappyIcon from '../assets/emojis/HappyIcon.svg'
110
102
  import { MESSAGE_TYPE_CODES } from '../resources/constants/message-type.constant';
111
- import Image from 'primevue/image';
112
103
 
113
- const emit = defineEmits(["loadMore", "retry", "onQualifying"]);
104
+ const emit = defineEmits(["loadMore", "retry", "onQualifying", "see"]);
114
105
  const props = defineProps({
115
106
  messages: {
116
107
  type: Array as PropType<Message[]>,
@@ -357,35 +348,10 @@ const emoji: { [key in string]: any } = {
357
348
  font-size: 2rem;
358
349
  }
359
350
 
360
- .flex {
361
- display: flex;
362
- flex-wrap: wrap;
363
- }
364
- .flex-col {
365
- flex-direction: column;
366
- }
367
- .items-center {
368
- align-items: center;
369
- }
370
- .gap-2 {
371
- gap: 0.5rem;
372
- }
373
-
374
- .mb-2 {
375
- margin-bottom: 8px;
376
- }
377
-
378
- .mt-2 {
379
- margin-top: 8px;
380
- }
381
-
382
351
  .content-disabled {
383
352
  -webkit-filter: grayscale(1); /* Google Chrome, Safari 6+ & Opera 15+ */
384
353
  filter: grayscale(1); /* Microsoft Edge and Firefox 35+ */
385
354
  opacity: 0.5;
386
355
  }
387
- .justify-between {
388
- justify-content: space-between;
389
- }
390
356
 
391
357
  </style>
@@ -1,10 +1,4 @@
1
1
  import { IPropsSidebar } from './IPropsSidebar';
2
- import { type DialogProps } from "primevue/dialog";
3
2
 
4
3
 
5
- export interface IPropsDialog extends Omit<IPropsSidebar, 'position'> {
6
- position?: DialogProps['position'];
7
-
8
- // solo para v-bind
9
- 'onUpdate:modelValue'?: (args: IPropsDialog['modelValue'])=> void
10
- }
4
+ export interface IPropsDialog extends IPropsSidebar {}
@@ -1,16 +1,12 @@
1
- import type { DrawerProps } from "primevue/drawer";
2
-
3
1
  export interface IPropsSidebar {
4
- modelValue: boolean;
5
- dismissable?: boolean;
6
- position?: DrawerProps['position'];
2
+ modelValue?: boolean;
7
3
  title?: string;
8
- isLoading?: boolean;
9
- hideActions?: boolean;
10
- hideHeader?: boolean;
11
- acceptFn?: () => Promise<boolean>;
12
- beforeAcceptFn?: () => Promise<boolean>;
13
- disable?: boolean;
4
+ // isLoading?: boolean;
5
+ // hideActions?: boolean;
6
+ // hideHeader?: boolean;
7
+ // acceptFn?: () => Promise<boolean>;
8
+ // beforeAcceptFn?: () => Promise<boolean>;
9
+ // disable?: boolean;
14
10
 
15
11
  // solo para v-bind
16
12
  'onUpdate:modelValue'?: (args: IPropsSidebar['modelValue'])=> void
@@ -1,82 +1,85 @@
1
1
  <template>
2
- <Dialog
3
- :visible="propsComponent.modelValue"
4
- :dismissable
5
- :position
6
- @update:visible="(val: boolean) => emit('update:modelValue', val)"
7
- class="!w-auto min-w-[20rem] dark:!bg-[var(--theme-background-secondary)]"
8
- >
9
- <template #container>
10
- <LoadingComponent v-if="propsComponent.isLoading || isWorking" />
11
- <SidebarHeader v-if="!propsComponent.hideHeader" :title :closeFn="() => emit('update:modelValue', false)" />
12
-
13
- <!-- <Divider class="!m-0 !p-0" /> -->
2
+ <div v-if="props.modelValue" class="dialog-overlay" @click="closeDialog">
3
+ <div class="dialog-content" @click.stop>
4
+ <div class="header-widget">
5
+ <h4 class="title-chat">{{ title }}</h4>
6
+ <button @click="() => closeDialog()" class="btn-close">
7
+ <IconClose class="pointer" />
8
+ </button>
9
+ </div>
14
10
 
15
- <div class="overflow-y-auto m-4 h-full max-h-full">
11
+ <div>
16
12
  <slot></slot>
17
13
  </div>
18
-
19
- <footer v-if="!hideActions" class="flex sm:justify-between gap-16 items-center mx-5 py-5">
20
- <Button
21
- label="Cancelar"
22
- severity="secondary"
23
- class="w-full h-[40px] !rounded-2xl pr-5 sm:max-w-48"
24
- icon="pi pi-times"
25
- outlined
26
- @click="() => emit('update:modelValue', false)"
27
- ></Button>
28
- <Button
29
- label="Aceptar"
30
- :disabled="disable || isLoading"
31
- icon="pi pi-check"
32
- aria-label="save"
33
- class="w-full h-[40px] !rounded-2xl pr-5 sm:max-w-48"
34
- @click="onAccept"
35
- ></Button>
36
- </footer>
37
- </template>
38
- </Dialog>
14
+ </div>
15
+ </div>
39
16
  </template>
40
17
 
41
- <script setup lang="ts">
42
- import Dialog from 'primevue/dialog';
18
+ <script lang="ts" setup>
19
+ import IconClose from '../IconClose.vue'
43
20
  import { IPropsDialog } from './IPropsDialog';
44
- import LoadingComponent from '../LoadingComponent.vue';
45
- import SidebarHeader from '../sidebar/SidebarHeader.vue';
46
- import { computed, ref } from 'vue';
47
- import Button from 'primevue/button';
48
21
 
49
- const propsComponent = withDefaults(defineProps<IPropsDialog>(), {
50
- beforeAcceptFn: async () => true
51
- });
22
+ const props = defineProps<IPropsDialog>()
52
23
 
53
- const emit = defineEmits<{
54
- 'update:modelValue': [visible: boolean];
55
- accept: [void];
56
- }>();
24
+ const emit = defineEmits(['update:modelValue']);
57
25
 
58
- const isWorking = ref(false);
59
- const isLoading = computed(() => {
60
- return isWorking.value || propsComponent.disable || propsComponent.isLoading;
61
- });
26
+ const closeDialog = () => {
27
+ emit("update:modelValue", false);
28
+ };
29
+ </script>
62
30
 
63
- async function onAccept() {
64
- if (!propsComponent.acceptFn) {
65
- emit('accept');
66
- return;
67
- }
31
+ <style scoped>
32
+ .dialog-overlay {
33
+ position: fixed;
34
+ top: 0;
35
+ left: 0;
36
+ width: 100%;
37
+ height: 100%;
38
+ background-color: rgba(0, 0, 0, 0.5);
39
+ display: flex;
40
+ justify-content: center;
41
+ align-items: center;
42
+ opacity: 0;
43
+ animation: fadeIn 0.3s forwards;
44
+ }
68
45
 
69
- const isPassed = await propsComponent.beforeAcceptFn();
46
+ .dialog-content {
47
+ background-color: white;
48
+ padding: 15px;
49
+ border-radius: 8px;
50
+ text-align: center;
51
+ animation: slideIn 0.3s ease-out forwards;
52
+ }
70
53
 
71
- if(!isPassed) return;
54
+ @keyframes fadeIn {
55
+ to {
56
+ opacity: 1;
57
+ }
58
+ }
72
59
 
73
- isWorking.value = true;
74
- const result = await propsComponent.acceptFn?.();
75
- isWorking.value = false;
60
+ @keyframes slideIn {
61
+ from {
62
+ transform: translateY(-50px);
63
+ }
64
+ to {
65
+ transform: translateY(0);
66
+ }
67
+ }
76
68
 
77
- if(!result) return
78
-
79
- emit('accept')
80
- emit('update:modelValue', false);
69
+ .dialog-overlay.v-enter-active,
70
+ .dialog-overlay.v-leave-active {
71
+ transition: opacity 0.3s;
81
72
  }
82
- </script>
73
+
74
+ .btn-close {
75
+ padding: 0;
76
+ background-color: transparent;
77
+ border: none;
78
+ display: flex;
79
+ align-items: center;
80
+ border-radius: 50%;
81
+ &:hover {
82
+ background-color: rgba(202, 202, 202, 0.534);
83
+ }
84
+ }
85
+ </style>
@@ -53,6 +53,24 @@
53
53
  @on-qualifying="(args)=> emit('onQualifying', args)"
54
54
  />
55
55
  </div>
56
+
57
+ <Button label="Show" @click="visible = true" />
58
+
59
+ <Dialog v-model:visible="visible" modal header="Edit Profile" :style="{ width: '25rem' }">
60
+ <span class="text-surface-500 dark:text-surface-400 block mb-8">Update your information.</span>
61
+ <div class="flex items-center gap-4 mb-4">
62
+ <label for="username" class="font-semibold w-24">Username</label>
63
+ <InputText id="username" class="flex-auto" autocomplete="off" />
64
+ </div>
65
+ <div class="flex items-center gap-4 mb-8">
66
+ <label for="email" class="font-semibold w-24">Email</label>
67
+ <InputText id="email" class="flex-auto" autocomplete="off" />
68
+ </div>
69
+ <div class="flex justify-end gap-2">
70
+ <Button type="button" label="Cancel" severity="secondary" @click="visible = false"></Button>
71
+ <Button type="button" label="Save" @click="visible = false"></Button>
72
+ </div>
73
+ </Dialog>
56
74
  </div>
57
75
  </template>
58
76
 
@@ -65,7 +83,7 @@ import IconWhatsApp from "./IconWhatsApp.vue";
65
83
  import IconChat from "./IconChat.vue";
66
84
 
67
85
  const emit = defineEmits(["show-toast", "show-confirm", "onQualifying"]);
68
-
86
+ const visible = ref(true);
69
87
  const enum MeansCommunication{
70
88
  WHATSAPP,
71
89
  TELEGRAM
@@ -1,21 +0,0 @@
1
- import { PropType } from 'vue';
2
- declare const _default: import('vue').DefineComponent<import('vue').ExtractPropTypes<{
3
- size: {
4
- type: PropType<"small" | "normal">;
5
- default: string;
6
- };
7
- footer_text: {
8
- type: StringConstructor;
9
- };
10
- }>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
11
- size: {
12
- type: PropType<"small" | "normal">;
13
- default: string;
14
- };
15
- footer_text: {
16
- type: StringConstructor;
17
- };
18
- }>> & Readonly<{}>, {
19
- size: "small" | "normal";
20
- }, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
21
- export default _default;
@@ -1,36 +0,0 @@
1
- import { PropType } from 'vue';
2
- declare function __VLS_template(): {
3
- attrs: Partial<{}>;
4
- slots: {
5
- content?(_: {}): any;
6
- };
7
- refs: {};
8
- rootEl: HTMLElement;
9
- };
10
- type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
11
- declare const __VLS_component: import('vue').DefineComponent<import('vue').ExtractPropTypes<{
12
- closeFn: {
13
- type: PropType<(event: Event) => void>;
14
- required: true;
15
- };
16
- title: {
17
- type: StringConstructor;
18
- required: false;
19
- };
20
- }>, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<import('vue').ExtractPropTypes<{
21
- closeFn: {
22
- type: PropType<(event: Event) => void>;
23
- required: true;
24
- };
25
- title: {
26
- type: StringConstructor;
27
- required: false;
28
- };
29
- }>> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLElement>;
30
- declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
31
- export default _default;
32
- type __VLS_WithTemplateSlots<T, S> = T & {
33
- new (): {
34
- $slots: S;
35
- };
36
- };
@@ -1,40 +0,0 @@
1
- <template>
2
- <header class="flex justify-between items-center border-b-2 p-2 pl-4 pb-0">
3
- <slot name="content">
4
- <span class="text-gray-500 dark:text-gray-200 text-xl font-roboto font-medium">
5
- {{ props.title }}
6
- </span>
7
- </slot>
8
- <Button
9
- icon="pi pi-times"
10
- severity="secondary"
11
- text
12
- rounded
13
- aria-label="Cancel"
14
- @click="props.closeFn"
15
- >
16
- <template #icon>
17
- <IconClose />
18
- </template>
19
- </Button>
20
- </header>
21
- </template>
22
-
23
- <script setup lang="ts">
24
- import Button from 'primevue/button';
25
- import IconClose from '../IconClose.vue';
26
- import { PropType } from 'vue';
27
-
28
- const props = defineProps({
29
- closeFn: {
30
- type: Function as PropType<(event: Event) => void>,
31
- required: true,
32
- },
33
- title: {
34
- type: String,
35
- required: false,
36
- },
37
- });
38
- </script>
39
-
40
- <style scoped></style>