@7365admin1/layer-common 3.0.26 → 3.0.28

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.
@@ -1,337 +1,417 @@
1
1
  <template>
2
- <v-card width="100%" :loading="processing">
3
- <v-toolbar>
4
- <v-row no-gutters class="fill-height px-6" align="center">
5
- <span class="font-weight-bold text-subtitle-1 text-capitalize">
6
- Preview Announcement
2
+ <v-card width="100%" :loading="processing">
3
+ <v-toolbar>
4
+ <v-row no-gutters class="fill-height px-6" align="center">
5
+ <span class="font-weight-bold text-subtitle-1 text-capitalize">
6
+ Preview Announcement
7
+ </span>
8
+ </v-row>
9
+ </v-toolbar>
10
+
11
+ <v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0 my-3">
12
+ <v-row no-gutters>
13
+ <template v-for="(label, key) in formattedFields" :key="key">
14
+ <v-col cols="12" class="mb-5">
15
+ <v-row no-gutters class="">
16
+ <v-col class="font-weight-bold">{{ label }}:</v-col>
17
+
18
+ <v-col cols="9" class="px-10">
19
+ <span v-if="key === 'content'" v-html="getFieldValue(key)" />
20
+ <span v-else-if="key === 'noExpiration'">
21
+ <BulletinExpirationChip
22
+ :value="getFieldValue(key) as boolean"
23
+ />
7
24
  </span>
25
+ <span v-else>
26
+ {{ getFieldValue(key) }}
27
+ </span>
28
+ </v-col>
8
29
  </v-row>
9
- </v-toolbar>
10
-
11
- <v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0 my-3">
12
- <v-row no-gutters>
13
- <template v-for="(label, key) in formattedFields" :key="key">
14
- <v-col cols="12" class="mb-5">
15
- <v-row no-gutters class="">
16
- <v-col class="font-weight-bold">{{ label }}:</v-col>
17
-
18
- <v-col cols="9" class="px-10">
19
- <span v-if="key === 'content'" v-html="getFieldValue(key)" />
20
- <span v-else-if="key === 'noExpiration'">
21
- <BulletinExpirationChip :value="getFieldValue(key) as boolean" />
22
- </span>
23
- <span v-else>
24
- {{ getFieldValue(key) }}
25
- </span>
26
- </v-col>
27
-
28
-
29
- </v-row>
30
- </v-col>
31
- </template>
32
-
33
- <v-col cols="12" v-if="prop.activeAnnouncement?.file?.length > 0" class="mb-5">
34
- <v-row no-gutters>
35
- <v-col class="font-weight-bold">Attachments:</v-col>
36
- <v-col cols="9" class="px-10">
37
-
38
- <template v-if="videosArray.length > 0">
39
- <div class="text-caption text-medium-emphasis mb-1">Videos ({{ videosArray.length }})</div>
40
- <v-list density="compact" class="pa-0 rounded-lg border mb-3">
41
- <template v-for="(item, i) in videosArray" :key="item._id">
42
- <v-divider v-if="i > 0" />
43
- <v-list-item
44
- :prepend-icon="getFileIcon(item.file.type)"
45
- :title="item.file.name"
46
- :subtitle="item.file.type"
47
- class="cursor-pointer"
48
- @click="openMediaViewer(item._id, 'media')"
49
- >
50
- <template #prepend>
51
- <v-icon :color="getFileIconColor(item.file.type)" class="mr-3">{{ getFileIcon(item.file.type) }}</v-icon>
52
- </template>
53
- <template #append>
54
- <v-icon size="16" color="grey-lighten-1">mdi-play-circle-outline</v-icon>
55
- </template>
56
- </v-list-item>
57
- </template>
58
- </v-list>
59
- </template>
60
-
61
- <template v-if="photosArray.length > 0">
62
- <div class="text-caption text-medium-emphasis mb-1" :class="{ 'mt-3': videosArray.length > 0 }">Photos ({{ photosArray.length }})</div>
63
- <v-list density="compact" class="pa-0 rounded-lg border mb-3">
64
- <template v-for="(item, i) in photosArray" :key="item._id">
65
- <v-divider v-if="i > 0" />
66
- <v-list-item
67
- class="cursor-pointer"
68
- @click="openMediaViewer(item._id, 'media')"
69
- >
70
- <template #prepend>
71
- <v-avatar size="36" rounded="sm" class="mr-3">
72
- <v-img :src="getFileUrl(item._id)" cover>
73
- <template #error>
74
- <v-icon color="green" size="20">mdi-image</v-icon>
75
- </template>
76
- </v-img>
77
- </v-avatar>
78
- </template>
79
- <v-list-item-title class="text-body-2">{{ item.file.name }}</v-list-item-title>
80
- <v-list-item-subtitle class="text-caption">{{ item.file.type }}</v-list-item-subtitle>
81
- <template #append>
82
- <v-icon size="16" color="grey-lighten-1">mdi-eye-outline</v-icon>
83
- </template>
84
- </v-list-item>
85
- </template>
86
- </v-list>
87
- </template>
88
-
89
- <template v-if="filesArray.length > 0">
90
- <div class="text-caption text-medium-emphasis mb-1" :class="{ 'mt-3': videosArray.length > 0 || photosArray.length > 0 }">Files ({{ filesArray.length }})</div>
91
- <v-list density="compact" class="pa-0 rounded-lg border">
92
- <template v-for="(item, i) in filesArray" :key="item._id">
93
- <v-divider v-if="i > 0" />
94
- <v-list-item
95
- class="cursor-pointer"
96
- @click="openFileViewer(item._id, item.file.name)"
97
- >
98
- <template #prepend>
99
- <v-icon :color="getFileIconColor(item.file.type)" class="mr-3">{{ getFileIcon(item.file.type) }}</v-icon>
100
- </template>
101
- <v-list-item-title class="text-body-2">{{ item.file.name }}</v-list-item-title>
102
- <v-list-item-subtitle class="text-caption">{{ item.file.type }}</v-list-item-subtitle>
103
- <template #append>
104
- <v-icon size="16" color="grey-lighten-1">mdi-open-in-new</v-icon>
105
- </template>
106
- </v-list-item>
107
- </template>
108
- </v-list>
30
+ </v-col>
31
+ </template>
32
+
33
+ <v-col
34
+ cols="12"
35
+ v-if="prop.activeAnnouncement?.file?.length > 0"
36
+ class="mb-5"
37
+ >
38
+ <v-row no-gutters>
39
+ <v-col class="font-weight-bold">Attachments:</v-col>
40
+ <v-col cols="9" class="px-10">
41
+ <template v-if="videosArray.length > 0">
42
+ <div class="text-caption text-medium-emphasis mb-1">
43
+ Videos ({{ videosArray.length }})
44
+ </div>
45
+ <v-list density="compact" class="pa-0 rounded-lg border mb-3">
46
+ <template v-for="(item, i) in videosArray" :key="item._id">
47
+ <v-divider v-if="i > 0" />
48
+ <v-list-item
49
+ :prepend-icon="getFileIcon(item.file.type)"
50
+ :title="item.file.name"
51
+ :subtitle="item.file.type"
52
+ class="cursor-pointer"
53
+ @click="openMediaViewer(item._id, 'media')"
54
+ >
55
+ <template #prepend>
56
+ <v-icon
57
+ :color="getFileIconColor(item.file.type)"
58
+ class="mr-3"
59
+ >{{ getFileIcon(item.file.type) }}</v-icon
60
+ >
61
+ </template>
62
+ <template #append>
63
+ <v-icon size="16" color="grey-lighten-1"
64
+ >mdi-play-circle-outline</v-icon
65
+ >
66
+ </template>
67
+ </v-list-item>
68
+ </template>
69
+ </v-list>
70
+ </template>
71
+
72
+ <template v-if="photosArray.length > 0">
73
+ <div
74
+ class="text-caption text-medium-emphasis mb-1"
75
+ :class="{ 'mt-3': videosArray.length > 0 }"
76
+ >
77
+ Photos ({{ photosArray.length }})
78
+ </div>
79
+ <v-list density="compact" class="pa-0 rounded-lg border mb-3">
80
+ <template v-for="(item, i) in photosArray" :key="item._id">
81
+ <v-divider v-if="i > 0" />
82
+ <v-list-item
83
+ class="cursor-pointer"
84
+ @click="openMediaViewer(item._id, 'media')"
85
+ >
86
+ <template #prepend>
87
+ <v-avatar size="36" rounded="sm" class="mr-3">
88
+ <v-img :src="getFileUrl(item._id)" cover>
89
+ <template #error>
90
+ <v-icon color="green" size="20">mdi-image</v-icon>
109
91
  </template>
110
-
111
- </v-col>
112
- </v-row>
113
- </v-col>
114
-
115
- <!-- Media Carousel (images + videos) -->
116
- <ImageCarousel v-model="showCarousel" :active-file-id="activeFileId" :files="carouselFiles" />
117
-
118
- <!-- File Viewer Dialog (PDF, docs, etc.) -->
119
- <v-dialog v-model="showFileDialog" max-width="900" scrollable>
120
- <v-card>
121
- <v-toolbar density="compact">
122
- <v-toolbar-title class="text-subtitle-2 text-truncate">{{ activeFileName }}</v-toolbar-title>
123
- <v-spacer />
124
- <v-btn icon="mdi-open-in-new" variant="text" size="small"
125
- @click="openInNewTab(activeFileId)" />
126
- <v-btn icon="mdi-close" variant="text" size="small"
127
- @click="showFileDialog = false" />
128
- </v-toolbar>
129
- <v-card-text class="pa-0" style="height: 75vh;">
130
- <iframe
131
- :src="getFileUrl(activeFileId)"
132
- width="100%"
133
- height="100%"
134
- style="border: none;"
135
- :title="activeFileName"
136
- />
137
- </v-card-text>
138
- <v-card-actions>
139
- <v-spacer />
140
- <v-btn variant="text" class="text-none" @click="openInNewTab(activeFileId)">
141
- <v-icon start>mdi-download</v-icon>
142
- Open / Download
143
- </v-btn>
144
- </v-card-actions>
145
- </v-card>
146
- </v-dialog>
147
- </v-row>
148
- </v-card-text>
149
-
150
- <v-toolbar class="pa-0" density="compact">
151
- <v-row no-gutters>
152
- <v-col :col="(!canUpdate && !canDelete) ? 12 : 6" class="pa-0">
153
- <v-btn block variant="text" height="48" class="text-none" @click="emit('close')">
154
- Close
155
- </v-btn>
156
- </v-col>
157
-
158
- <v-col v-if="canUpdate || canDelete" cols="6" class="pa-0">
159
- <v-menu contained>
160
- <template #activator="{ props }">
161
- <v-btn block variant="flat" color="black" height="48" class="text-none" tile v-bind="props">
162
- More actions
163
- </v-btn>
164
- </template>
165
-
166
- <v-list class="pa-0">
167
- <v-list-item v-if="canUpdate" @click="handleEdit">
168
- <v-list-item-title class="text-subtitle-2">
169
- Edit Announcement
170
- </v-list-item-title>
171
- </v-list-item>
172
-
173
- <v-list-item v-if="canDelete" class="text-red" @click="handleDelete">
174
- <v-list-item-title class="text-subtitle-2">
175
- Delete Announcement
176
- </v-list-item-title>
177
- </v-list-item>
178
- </v-list>
179
- </v-menu>
180
- </v-col>
181
- </v-row>
182
- </v-toolbar>
183
- </v-card>
92
+ </v-img>
93
+ </v-avatar>
94
+ </template>
95
+ <v-list-item-title class="text-body-2">{{
96
+ item.file.name
97
+ }}</v-list-item-title>
98
+ <v-list-item-subtitle class="text-caption">{{
99
+ item.file.type
100
+ }}</v-list-item-subtitle>
101
+ <template #append>
102
+ <v-icon size="16" color="grey-lighten-1"
103
+ >mdi-eye-outline</v-icon
104
+ >
105
+ </template>
106
+ </v-list-item>
107
+ </template>
108
+ </v-list>
109
+ </template>
110
+
111
+ <template v-if="filesArray.length > 0">
112
+ <div
113
+ class="text-caption text-medium-emphasis mb-1"
114
+ :class="{
115
+ 'mt-3': videosArray.length > 0 || photosArray.length > 0,
116
+ }"
117
+ >
118
+ Files ({{ filesArray.length }})
119
+ </div>
120
+ <v-list density="compact" class="pa-0 rounded-lg border">
121
+ <template v-for="(item, i) in filesArray" :key="item._id">
122
+ <v-divider v-if="i > 0" />
123
+ <v-list-item
124
+ class="cursor-pointer"
125
+ @click="openFileViewer(item._id, item.file.name)"
126
+ >
127
+ <template #prepend>
128
+ <v-icon
129
+ :color="getFileIconColor(item.file.type)"
130
+ class="mr-3"
131
+ >{{ getFileIcon(item.file.type) }}</v-icon
132
+ >
133
+ </template>
134
+ <v-list-item-title class="text-body-2">{{
135
+ item.file.name
136
+ }}</v-list-item-title>
137
+ <v-list-item-subtitle class="text-caption">{{
138
+ item.file.type
139
+ }}</v-list-item-subtitle>
140
+ <template #append>
141
+ <v-icon size="16" color="grey-lighten-1"
142
+ >mdi-open-in-new</v-icon
143
+ >
144
+ </template>
145
+ </v-list-item>
146
+ </template>
147
+ </v-list>
148
+ </template>
149
+ </v-col>
150
+ </v-row>
151
+ </v-col>
152
+
153
+ <!-- Media Carousel (images + videos) -->
154
+ <ImageCarousel
155
+ v-model="showCarousel"
156
+ :active-file-id="activeFileId"
157
+ :files="carouselFiles"
158
+ />
159
+
160
+ <!-- File Viewer Dialog (PDF, docs, etc.) -->
161
+ <v-dialog v-model="showFileDialog" max-width="900" scrollable>
162
+ <v-card>
163
+ <v-toolbar density="compact">
164
+ <v-toolbar-title class="text-subtitle-2 text-truncate">{{
165
+ activeFileName
166
+ }}</v-toolbar-title>
167
+ <v-spacer />
168
+ <v-btn
169
+ icon="mdi-open-in-new"
170
+ variant="text"
171
+ size="small"
172
+ @click="openInNewTab(activeFileId)"
173
+ />
174
+ <v-btn
175
+ icon="mdi-close"
176
+ variant="text"
177
+ size="small"
178
+ @click="showFileDialog = false"
179
+ />
180
+ </v-toolbar>
181
+ <v-card-text class="pa-0" style="height: 75vh">
182
+ <iframe
183
+ :src="getFileUrl(activeFileId)"
184
+ width="100%"
185
+ height="100%"
186
+ style="border: none"
187
+ :title="activeFileName"
188
+ />
189
+ </v-card-text>
190
+ <v-card-actions>
191
+ <v-spacer />
192
+ <v-btn
193
+ variant="text"
194
+ class="text-none"
195
+ @click="openInNewTab(activeFileId)"
196
+ >
197
+ <v-icon start>mdi-download</v-icon>
198
+ Open / Download
199
+ </v-btn>
200
+ </v-card-actions>
201
+ </v-card>
202
+ </v-dialog>
203
+ </v-row>
204
+ </v-card-text>
205
+
206
+ <v-toolbar class="pa-0" density="compact">
207
+ <v-row no-gutters>
208
+ <v-col :col="!canUpdate && !canDelete ? 12 : 6" class="pa-0">
209
+ <v-btn
210
+ block
211
+ variant="text"
212
+ height="48"
213
+ class="text-none"
214
+ @click="emit('close')"
215
+ >
216
+ Close
217
+ </v-btn>
218
+ </v-col>
219
+
220
+ <v-col v-if="canUpdate || canDelete" cols="6" class="pa-0">
221
+ <v-menu contained>
222
+ <template #activator="{ props }">
223
+ <v-btn
224
+ block
225
+ variant="flat"
226
+ color="black"
227
+ height="48"
228
+ class="text-none"
229
+ tile
230
+ v-bind="props"
231
+ >
232
+ More actions
233
+ </v-btn>
234
+ </template>
235
+
236
+ <v-list class="pa-0">
237
+ <v-list-item v-if="canUpdate" @click="handleEdit">
238
+ <v-list-item-title class="text-subtitle-2">
239
+ Edit Announcement
240
+ </v-list-item-title>
241
+ </v-list-item>
242
+
243
+ <v-list-item
244
+ v-if="canDelete"
245
+ class="text-red"
246
+ @click="handleDelete"
247
+ >
248
+ <v-list-item-title class="text-subtitle-2">
249
+ Delete Announcement
250
+ </v-list-item-title>
251
+ </v-list-item>
252
+ </v-list>
253
+ </v-menu>
254
+ </v-col>
255
+ </v-row>
256
+ </v-toolbar>
257
+ </v-card>
184
258
  </template>
185
259
 
186
-
187
260
  <script setup lang="ts">
188
-
189
261
  const prop = defineProps({
190
- activeAnnouncement: {
191
- type: Object as PropType<TAnnouncement>,
192
- required: true
193
- },
194
- canUpdate: Boolean,
195
- canDelete: Boolean,
196
- })
262
+ activeAnnouncement: {
263
+ type: Object as PropType<TAnnouncement>,
264
+ required: true,
265
+ },
266
+ canUpdate: Boolean,
267
+ canDelete: Boolean,
268
+ });
197
269
 
198
- const processing = ref(false)
199
- const { recipientList } = useBulletin()
200
- const { getFileUrl, urlToFile } = useFile()
270
+ const processing = ref(false);
271
+ const { recipientList } = useBulletin();
272
+ const { getFileUrl, urlToFile } = useFile();
201
273
 
202
- const emit = defineEmits(['close', 'edit', 'delete'])
274
+ const emit = defineEmits(["close", "edit", "delete"]);
203
275
 
204
276
  /* Field labels */
205
277
  const formattedFields: Partial<Record<keyof TAnnouncement, string>> = {
206
- title: "Title",
207
- createdAt: "Date Created",
208
- recipients: "Recipients",
209
- content: "Content",
210
- startDate: "Start Date",
211
- endDate: "End Date",
212
- noExpiration: "No Expiration",
213
- }
278
+ title: "Title",
279
+ createdAt: "Date Created",
280
+ recipients: "Recipients",
281
+ content: "Content",
282
+ startDate: "Start Date",
283
+ endDate: "End Date",
284
+ noExpiration: "No Expiration",
285
+ };
214
286
 
215
287
  const formattedRecipients = computed(() => {
216
- const arr = recipientList.filter(x =>
217
- prop.activeAnnouncement?.recipients?.includes(x.value)
218
- )
219
- return arr.map(item => item.title).join(", ")
220
- })
288
+ const arr = recipientList.filter((x) =>
289
+ prop.activeAnnouncement?.recipients?.includes(x.value)
290
+ );
291
+ return arr.map((item) => item.title).join(", ");
292
+ });
221
293
 
222
294
  function getFieldValue(key: keyof TAnnouncement) {
223
- const value = prop.activeAnnouncement?.[key]
224
-
225
- if (value === null || value === "" || value === undefined) return ""
226
-
227
- switch (key) {
228
- case "recipients":
229
- return formattedRecipients.value
230
- case "createdAt":
231
- case "startDate":
232
- case "endDate":
233
- return toLocalDate(value as string)
234
- default:
235
- return value
236
- }
295
+ const value = prop.activeAnnouncement?.[key];
296
+
297
+ if (value === null || value === "" || value === undefined) return "";
298
+
299
+ switch (key) {
300
+ case "recipients":
301
+ return formattedRecipients.value;
302
+ case "createdAt":
303
+ case "startDate":
304
+ case "endDate":
305
+ return toLocalDate(value as string);
306
+ default:
307
+ return value;
308
+ }
237
309
  }
238
310
 
239
- const rawFileArray = ref<{ file: File, _id: string, preview: boolean }[]>([])
311
+ const rawFileArray = ref<{ file: File; _id: string; preview: boolean }[]>([]);
240
312
 
241
- const photosArray = getByType('image/')
242
- const videosArray = getByType('video/')
243
- const filesArray = getByType('other')
313
+ const photosArray = getByType("image/");
314
+ const videosArray = getByType("video/");
315
+ const filesArray = getByType("other");
244
316
 
245
317
  /* Viewer state */
246
- const showCarousel = ref(false)
247
- const showFileDialog = ref(false)
248
- const activeFileId = ref('')
249
- const activeFileName = ref('')
250
- const carouselFiles = ref<string[]>([])
251
-
252
- function openMediaViewer(id: string, _type: 'media') {
253
- activeFileId.value = id
254
- carouselFiles.value = [
255
- ...photosArray.value.map(x => x._id),
256
- ...videosArray.value.map(x => x._id),
257
- ]
258
- showCarousel.value = true
318
+ const showCarousel = ref(false);
319
+ const showFileDialog = ref(false);
320
+ const activeFileId = ref("");
321
+ const activeFileName = ref("");
322
+ const carouselFiles = ref<string[]>([]);
323
+
324
+ function openMediaViewer(id: string, _type: "media") {
325
+ activeFileId.value = id;
326
+ carouselFiles.value = [
327
+ ...photosArray.value.map((x) => x._id),
328
+ ...videosArray.value.map((x) => x._id),
329
+ ];
330
+ showCarousel.value = true;
259
331
  }
260
332
 
261
333
  function openFileViewer(id: string, name: string) {
262
- activeFileId.value = id
263
- activeFileName.value = name
264
- showFileDialog.value = true
334
+ activeFileId.value = id;
335
+ activeFileName.value = name;
336
+ showFileDialog.value = true;
265
337
  }
266
338
 
267
339
  function openInNewTab(id: string) {
268
- window.open(getFileUrl(id), '_blank', 'noopener,noreferrer')
340
+ window.open(getFileUrl(id), "_blank", "noopener,noreferrer");
269
341
  }
270
342
 
271
343
  function getFileIcon(mimeType: string): string {
272
- if (mimeType.startsWith('image/')) return 'mdi-image'
273
- if (mimeType.startsWith('video/')) return 'mdi-video'
274
- if (mimeType === 'application/pdf') return 'mdi-file-pdf-box'
275
- if (mimeType.includes('word') || mimeType.includes('document')) return 'mdi-file-word-box'
276
- if (mimeType.includes('excel') || mimeType.includes('spreadsheet')) return 'mdi-file-excel-box'
277
- if (mimeType.includes('powerpoint') || mimeType.includes('presentation')) return 'mdi-file-powerpoint-box'
278
- if (mimeType === 'text/plain') return 'mdi-file-document-outline'
279
- if (mimeType.includes('zip') || mimeType.includes('compressed') || mimeType.includes('archive')) return 'mdi-folder-zip-outline'
280
- return 'mdi-file-outline'
344
+ if (mimeType.startsWith("image/")) return "mdi-image";
345
+ if (mimeType.startsWith("video/")) return "mdi-video";
346
+ if (mimeType === "application/pdf") return "mdi-file-pdf-box";
347
+ if (mimeType.includes("word") || mimeType.includes("document"))
348
+ return "mdi-file-word-box";
349
+ if (mimeType.includes("excel") || mimeType.includes("spreadsheet"))
350
+ return "mdi-file-excel-box";
351
+ if (mimeType.includes("powerpoint") || mimeType.includes("presentation"))
352
+ return "mdi-file-powerpoint-box";
353
+ if (mimeType === "text/plain") return "mdi-file-document-outline";
354
+ if (
355
+ mimeType.includes("zip") ||
356
+ mimeType.includes("compressed") ||
357
+ mimeType.includes("archive")
358
+ )
359
+ return "mdi-folder-zip-outline";
360
+ return "mdi-file-outline";
281
361
  }
282
362
 
283
363
  function getFileIconColor(mimeType: string): string {
284
- if (mimeType === 'application/pdf') return 'red'
285
- if (mimeType.includes('word') || mimeType.includes('document')) return 'blue'
286
- if (mimeType.includes('excel') || mimeType.includes('spreadsheet')) return 'green'
287
- if (mimeType.includes('powerpoint') || mimeType.includes('presentation')) return 'orange'
288
- if (mimeType.startsWith('video/')) return 'purple'
289
- return 'grey'
364
+ if (mimeType === "application/pdf") return "red";
365
+ if (mimeType.includes("word") || mimeType.includes("document")) return "blue";
366
+ if (mimeType.includes("excel") || mimeType.includes("spreadsheet"))
367
+ return "green";
368
+ if (mimeType.includes("powerpoint") || mimeType.includes("presentation"))
369
+ return "orange";
370
+ if (mimeType.startsWith("video/")) return "purple";
371
+ return "grey";
290
372
  }
291
373
 
292
- function getByType(prefix: 'image/' | 'video/' | 'other') {
293
- return computed(() => {
294
- return rawFileArray.value.filter(x => {
295
- const type = x?.file?.type
296
- if (typeof type !== 'string') return false
297
-
298
- if (prefix === 'other') {
299
- return !type.startsWith('image/') && !type.startsWith('video/')
300
- }
301
- return type.startsWith(prefix)
302
- })
303
- })
374
+ function getByType(prefix: "image/" | "video/" | "other") {
375
+ return computed(() => {
376
+ return rawFileArray.value.filter((x) => {
377
+ const type = x?.file?.type;
378
+ if (typeof type !== "string") return false;
379
+
380
+ if (prefix === "other") {
381
+ return !type.startsWith("image/") && !type.startsWith("video/");
382
+ }
383
+ return type.startsWith(prefix);
384
+ });
385
+ });
304
386
  }
305
387
 
306
388
  function toLocalDate(utcString: string) {
307
- if (typeof utcString !== 'string') return;
308
- return new Date(utcString).toLocaleString("en-US", {
309
- year: "numeric",
310
- month: "2-digit",
311
- day: "2-digit",
312
- })
389
+ if (typeof utcString !== "string") return;
390
+ return new Date(utcString).toLocaleDateString("en-GB", {
391
+ year: "numeric",
392
+ month: "2-digit",
393
+ day: "2-digit",
394
+ });
313
395
  }
314
396
 
315
397
  function handleEdit() {
316
- emit("edit")
398
+ emit("edit");
317
399
  }
318
400
 
319
401
  function handleDelete() {
320
- emit("delete")
402
+ emit("delete");
321
403
  }
322
404
 
323
405
  watchEffect(async () => {
324
- const data = prop.activeAnnouncement
325
- if (!data) return
326
-
327
- rawFileArray.value = await Promise.all(
328
- data.file.map(async (item) => {
329
- const fileUrl = getFileUrl(item._id)
330
- const file = await urlToFile(fileUrl, item.name)
331
- return { file, _id: item._id, preview: item.preview ?? false }
332
- })
333
- )
334
- })
335
-
336
-
406
+ const data = prop.activeAnnouncement;
407
+ if (!data) return;
408
+
409
+ rawFileArray.value = await Promise.all(
410
+ data.file.map(async (item) => {
411
+ const fileUrl = getFileUrl(item._id);
412
+ const file = await urlToFile(fileUrl, item.name);
413
+ return { file, _id: item._id, preview: item.preview ?? false };
414
+ })
415
+ );
416
+ });
337
417
  </script>