Skip to content

Commit 835d1b9

Browse files
Reecriture option api (#39)
* change lifesteps * daysjs clear * change inject types searchfilters * fix types in right select * Reorganise code in threads * fix mail button size + type iframe ref * type refs * correct api call * fix type + refactor api calls * types fixs * refactoring ticket page * WIP Mails + fix dto --------- Co-authored-by: Tacx <12997062+tacxou@users.noreply.github.com>
1 parent 22cf687 commit 835d1b9

File tree

22 files changed

+504
-417
lines changed

22 files changed

+504
-417
lines changed

app/nuxt.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import pugPlugin from 'vite-plugin-pug'
33
import openapiTS from 'openapi-typescript'
44
import { writeFileSync } from 'fs'
55
import { resolve } from 'path'
6-
import timezone from 'dayjs/plugin/timezone'
76

87
const TK_APP_API_URL = process.env.TK_APP_API_URL || 'http://localhost:7100'
98

app/src/components/searchfilters/Main.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import { pushQuery } from '~/composables'
3737
import type { Filter, Field, Comparator, SearchFilter } from '~/types'
3838
const dayjs = useDayjs()
3939
40-
const fields = inject('fieldsList', ref<Field[]>([]))
40+
const fields = inject<Field[]>('fieldsList')
4141
4242
const router = useRouter()
4343
const route = useRoute()
@@ -160,7 +160,7 @@ const searchInputType = computed(() => {
160160
161161
const fieldsFilteredByType = computed(() => {
162162
if (fieldType.value === undefined || fieldType.value === null) return []
163-
return fields.value.filter((field) => {
163+
return fields?.filter((field) => {
164164
return field.type === fieldType.value
165165
})
166166
})

app/src/components/searchfilters/RightSelect.vue

Lines changed: 7 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ import { useRoute, useRouter } from 'nuxt/app';
3030
import { ticketType, lifeSteps } from "#imports";
3131
type Category = components['schemas']['CategoriesDto']
3232
type State = components['schemas']['StatesDto']
33+
type CateforyFetch = components["schemas"]["PaginatedResponseDto"] & { data: Category[] }
34+
type StateFetch = components["schemas"]["PaginatedResponseDto"] & { data: State[] }
3335
3436
type Option = {
3537
label: string
@@ -42,8 +44,8 @@ type Option = {
4244
const route = useRoute()
4345
const router = useRouter()
4446
45-
const { data: statesData } = inject('stateFetch')
46-
const { data: categoriesData } = inject('categoriesFetch')
47+
const { data: statesData } = inject('stateFetch') as StateFetch
48+
const { data: categoriesData } = inject('categoriesFetch') as CateforyFetch
4749
4850
onMounted(() => {
4951
getFilters()
@@ -54,28 +56,7 @@ watch(() => route.query, () => {
5456
getFilters()
5557
})
5658
57-
// const getFilters = () => {
58-
// const query = { ...route.query }
59-
// for (const key in query) {
60-
// if (key.startsWith('filters[@') && query[key] !== null) {
61-
// const values = query[key]
62-
// if (Array.isArray(values)) {
63-
// for (const value of values) {
64-
// const option = options.value.find(option => option.value === value)
65-
// if (option) {
66-
// filters.value.push(option)
67-
// }
68-
// }
69-
// } else {
70-
// const option = options.value.find(option => option.value === values)
71-
// if (option) {
72-
// filters.value.push(option)
73-
// }
74-
// }
75-
// }
76-
// }
77-
// }
78-
59+
const filters = ref<Option[]>([])
7960
const getFilters = () => {
8061
// Use destructuring assignment to clone the route.query object
8162
const query = { ...route.query };
@@ -90,12 +71,11 @@ const getFilters = () => {
9071
})
9172
.flat()
9273
.map(value => options.value.find(option => option.value?.toString() === value?.toString() && option.group === group))
93-
.filter(option => option !== undefined);
74+
.filter(option => option !== undefined) as Option[]
9475
filters.value = filteredOptions;
9576
}
9677
9778
98-
const filters = ref<Option[]>([])
9979
const options = computed(() => {
10080
// const categories: Option[] = categoriesData.value.data.map((category: Category) => {
10181
// return {
@@ -125,7 +105,7 @@ const options = computed(() => {
125105
}
126106
}) ?? []
127107
if (!states.find(state => state.header)) states.unshift({ label: 'États', header: true })
128-
if (!lifeSteps.find(lifestepstep => lifestepstep.header)) lifeSteps.unshift({ label: 'Étapes de vie', header: true })
108+
if (!lifeSteps.find(lifestep => lifestep.header)) lifeSteps.unshift({ label: 'Étapes de vie', header: true })
129109
return [
130110
...lifeSteps,
131111
...ticketTypeOptions,
@@ -145,41 +125,6 @@ const regroupFilters = async () => {
145125
}, {})
146126
}
147127
148-
// const pushQuery = async () => {
149-
// const query = { ...route.query };
150-
// const regroupedFilters = await regroupFilters();
151-
152-
// const keysToDelete = new Set<string>();
153-
154-
// for (const key in query) {
155-
// if (key.startsWith('filters[@')) {
156-
// keysToDelete.add(key);
157-
// }
158-
// }
159-
160-
// keysToDelete.forEach((keyToDelete) => {
161-
// delete query[keyToDelete];
162-
// });
163-
164-
// for (const key in regroupedFilters) {
165-
// const values = regroupedFilters[key];
166-
// const length = values.length;
167-
// const keyWithBrackets = `${key}[]`;
168-
// if (length === 1) {
169-
// query[keyWithBrackets] = values;
170-
// } else {
171-
// if (query[keyWithBrackets]) {
172-
// delete query[keyWithBrackets];
173-
// }
174-
// query[key] = values;
175-
// }
176-
// }
177-
178-
// router.push({
179-
// query
180-
// })
181-
// };
182-
183128
const pushQueries = async () => {
184129
const regroupedFilters = await regroupFilters();
185130
for (const key in regroupedFilters) {

app/src/components/searchfilters/index.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ type MainData = {
2525
const dayjs = useDayjs()
2626
const router = useRouter()
2727
const route = useRoute()
28-
const fields = inject('fieldsList', ref<Field[]>([]))
28+
const fields = inject<Field[]>('fieldsList')
2929
const mainData = ref<MainData>()
3030
3131
const parseSimpleFilter = (searchFilter: SearchFilter) => {
@@ -86,7 +86,7 @@ const optionsRegrouped = (): { name: string, label: { label: string, value: stri
8686
const getAllFields = () => {
8787
const rightSelectOptions = optionsRegrouped()
8888
return [
89-
...fields.value,
89+
...fields,
9090
...rightSelectOptions
9191
]
9292
}

app/src/components/threads/Editor.vue

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,6 @@
6161
.row
6262
q-btn(label="Envoyer en note interne" color="primary" icon="mdi-note" @click="sendMessage(ThreadType.INTERNAL)" :disable="isDisabledTicket").col-6
6363
q-btn(label="Envoyer par mail" color="primary" icon="mdi-email" @click="sendMessage(ThreadType.OUTGOING)" :disable="isDisabledTicket").col-6
64-
//- .col-1(ref="dropZoneRef").bg-grey-3.items-center.justify-center.q-pa-md
65-
//- q-icon(name="mdi-paperclip" size="md" :class="isOverDropZone ? 'text-primary' : 'text-grey-5'")
66-
//- span.q-ml-md(:class="isOverDropZone ? 'text-primary' : 'text-grey-5'") Déposer un fichier
67-
6864
</template>
6965

7066
<script lang="ts" setup>
@@ -80,11 +76,8 @@ import { FsType } from '~/utils'
8076
import { useQuasar } from 'quasar';
8177
import ObjectID from 'bson-objectid';
8278
83-
type ThreadCreateDto = components['schemas']['ThreadCreateDto']
84-
type FsPart = components["schemas"]["IdfsPartDto"]
85-
type MailinfoPartDto = components["schemas"]["MailinfoPartDto"]
86-
8779
const emit = defineEmits(['refreshThreadsList'])
80+
const isDisabledTicket = inject<boolean>('isDisabledTicket')
8881
8982
const dayjs = useDayjs()
9083
const store = usePinia()
@@ -96,21 +89,7 @@ onMounted(() => {
9689
currentThreadId.value = generateMongoId()
9790
})
9891
99-
const threadType = ref(threadTypes[0])
100-
const isFullscreen = ref(false)
101-
const message = ref('')
102-
const dropZoneRef = ref<HTMLDivElement>()
103-
const dropZoneDialogRef = ref<HTMLDivElement>()
104-
const editorDialog = ref()
105-
const currentThreadId = ref<ObjectID | null>(null)
106-
const attachements = ref<FsPart[]>([])
107-
const mailInfo = ref({
108-
from: '',
109-
to: '',
110-
cc: '',
111-
subject: ''
112-
})
113-
92+
// Manage dropzone
11493
const onDrop = (files: File[] | null) => {
11594
if (isDisabledTicket) {
11695
$q.notify({
@@ -130,19 +109,25 @@ const onDrop = (files: File[] | null) => {
130109
uploadFile(file)
131110
}
132111
}
133-
112+
const dropZoneRef = ref<HTMLDivElement>()
113+
const dropZoneDialogRef = ref<HTMLDivElement>()
134114
const { isOverDropZone } = useDropZone(dropZoneRef, onDrop)
135115
const { isOverDropZone: isOverDropZoneDialog } = useDropZone(dropZoneDialogRef, onDrop)
136116
117+
// Manage attachements
118+
type FsPart = components["schemas"]["IdfsPartDto"]
119+
type FilestorageCreateDto = components["schemas"]["FilestorageCreateDto"]
120+
const attachements = ref<FsPart[]>([])
121+
const currentThreadId = ref<ObjectID | null>(null)
137122
const uploadFile = async (file: File) => {
138123
const formData = new FormData()
139124
formData.append('file', file)
140125
formData.append('namespace', 's3')
141-
formData.append('path', `/ticket/${route.params.id}/attachement/${currentThreadId}/${file.name}`)
126+
formData.append('path', `/ticket/${route.params.id}/attachement/${currentThreadId.value}/${file.name}`)
142127
formData.append('type', FsType.FILE)
143-
const { data, error } = await useHttpApi(`core/filestorage`, {
128+
const { data, error } = await useHttpApi(`/core/filestorage`, {
144129
method: 'post',
145-
body: formData
130+
body: formData as unknown as FilestorageCreateDto
146131
})
147132
if (error.value) {
148133
$q.notify({
@@ -151,27 +136,24 @@ const uploadFile = async (file: File) => {
151136
})
152137
return
153138
}
139+
const id = generateMongoId(data.value?.data?._id).toHexString()
154140
const fsPart: FsPart = {
155-
id: data.value?.data._id,
141+
id,
156142
name: file.name,
157-
namespace: data.value?.data.namespace,
158-
path: data.value?.data.path,
159-
mime: data.value?.data.mime
143+
namespace: data.value?.data?.namespace || '',
144+
path: data.value?.data?.path || '',
145+
mime: data.value?.data?.mime || '',
160146
}
161147
attachements.value.push(fsPart)
162148
$q.notify('Fichier envoyé')
163149
}
164150
165-
const emailReponse = (data: MailinfoPartDto) => {
166-
mailInfo.value.to = data.from.address
167-
mailInfo.value.from = data.to[0].address
168-
mailInfo.value.subject = data.subject.startsWith('Re:') ? data.subject : `Re:${data.subject}`
169-
isFullscreen.value = true
170-
}
171-
172151
const removeAttachment = (id: string) => {
173-
const { data, error } = useHttpApi(`core/filestorage/${id}`, {
174-
method: 'delete'
152+
const { data, error } = useHttpApi(`/core/filestorage/{_id}`, {
153+
method: 'delete',
154+
pathParams: {
155+
_id: id
156+
}
175157
})
176158
if (error.value) {
177159
$q.notify({
@@ -180,19 +162,38 @@ const removeAttachment = (id: string) => {
180162
})
181163
return
182164
}
183-
attachements.value = attachements.value.filter(attachement => attachement.id !== id)
165+
attachements.value = attachements.value.filter(attachement => `${attachement.id}` !== id)
184166
$q.notify('Fichier supprimé')
185167
}
186168
187-
const sendMessage = (type: ThreadType = ThreadType.OUTGOING) => {
188-
const { data: thread, error } = useHttpApi(`tickets/thread`, {
169+
const editorDialog = ref()
170+
const isFullscreen = ref(false)
171+
const mailInfo = ref({
172+
from: '',
173+
to: '',
174+
cc: '',
175+
subject: ''
176+
})
177+
type MailinfoPartDto = components["schemas"]["MailinfoPartDto"]
178+
const emailReponse = (data: MailinfoPartDto) => {
179+
mailInfo.value.to = data.from.address
180+
mailInfo.value.from = data.to[0].address
181+
mailInfo.value.subject = data.subject.startsWith('Re:') ? data.subject : `Re:${data.subject}`
182+
isFullscreen.value = true
183+
}
184+
185+
// Manage editor
186+
const threadType = ref(threadTypes[0])
187+
const message = ref('')
188+
async function sendMessage(type: ThreadType = ThreadType.OUTGOING) {
189+
const { data: thread, error } = await useHttpApi(`/tickets/thread`, {
189190
method: 'post',
190191
body: {
191-
_id: currentThreadId.value,
192+
_id: currentThreadId.value?.toHexString(),
192193
attachments: attachements.value,
193-
ticketId: generateMongoId(route.params.id.toString()),
194+
ticketId: generateStringMongoId(route.params.id.toString()),
194195
fragments: [{
195-
id: generateMongoId(),
196+
id: generateStringMongoId(),
196197
disposition: 'raw',
197198
message: message.value
198199
}],
@@ -206,7 +207,10 @@ const sendMessage = (type: ThreadType = ThreadType.OUTGOING) => {
206207
}
207208
})
208209
209-
if (error && error.value) {
210+
console.log('thread', thread.value)
211+
console.log('error', error.value)
212+
213+
if (error.value) {
210214
$q.notify({
211215
message: 'Impossible d\'envoyer le message',
212216
type: 'negative'
@@ -224,7 +228,6 @@ const sendMessage = (type: ThreadType = ThreadType.OUTGOING) => {
224228
})
225229
emit('refreshThreadsList')
226230
}
227-
228231
const editorDefinitions = computed(() => (
229232
{
230233
fullscreen: {
@@ -236,13 +239,10 @@ const editorDefinitions = computed(() => (
236239
}
237240
}
238241
}))
239-
240242
const editorToolbar = computed(() => {
241243
return [['left', 'center', 'right', 'justify'], ['bold', 'italic', 'underline', 'strike'], ['undo', 'redo'], ['fullscreen']]
242244
})
243245
244-
const isDisabledTicket = inject('isDisabledTicket')
245-
246246
defineExpose({
247247
emailReponse
248248
})

0 commit comments

Comments
 (0)