refactor, add post edit and delete, merge APIs, add not found view

Signed-off-by: Nicolas Froger <nicolas@kektus.xyz>
This commit is contained in:
Nicolas Froger 2024-07-27 02:20:08 +02:00
commit efde8738a8
No known key found for this signature in database
23 changed files with 803 additions and 343 deletions

View file

@ -25,18 +25,20 @@ import {
} from '@/components/ui/carousel/index.js'
import { Card, CardContent } from '@/components/ui/card/index.js'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert/index.js'
import { useAuthStore } from '@/stores/auth.js'
import { API_BASE_URL, S3_BUCKET, S3_ENDPOINT } from '@/config.js'
import { getCityAndCountry } from '@/lib/utils.js'
import { useAdminPostsStore } from '@/stores/adminPosts.js'
const authStore = useAuthStore()
const adminPostStore = useAdminPostsStore()
const formSchema = toTypedSchema(z.object({
description: z.string().min(1),
latitude: z.number(),
longitude: z.number(),
city: z.string().min(1),
country: z.string().min(1)
}))
const formSchema = toTypedSchema(
z.object({
description: z.string().min(1),
latitude: z.number(),
longitude: z.number(),
city: z.string().min(1),
country: z.string().min(1)
})
)
const form = useForm({
validationSchema: formSchema
})
@ -53,96 +55,18 @@ const formStatus = ref({
errorMsg: ''
})
function formError(message) {
formStatus.value.sending = false
formStatus.value.error = true
formStatus.value.errorMsg = message
formContainer.value.classList.remove('invisible')
}
const onSubmit = form.handleSubmit(async (values) => {
if (!authStore.isAuth)
return
console.log('Envoi du post...')
if (selectedFiles.value.length === 0)
return
formContainer.value.classList.add('hidden')
formStatus.value.sending = true
try {
await adminPostStore.createPost(values, selectedFiles.value)
} catch (e) {
formStatus.value.sending = false
formStatus.value.error = true
formStatus.value.errorMsg = e.message
formContainer.value.classList.remove('invisible')
const assets = []
for (const file of selectedFiles.value) {
console.log('Contact API asset')
const response = await fetch(API_BASE_URL + '/admin/assets', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-admin-token': authStore.adminToken
},
body: JSON.stringify({ filename: file.file.name })
}).catch((e) => {
console.log('Contact API asset failed: ' + e)
formError('Erreur à la préparation de l\'envoi d\'un média : ' + e)
})
if (!response)
return
if (!response.ok) {
console.log('Contact API asset failed: ' + response.statusText + '\n\n' + response.body)
formError('Erreur à la préparation de l\'envoi d\'un média : ' + response.statusText)
return
}
const responseBody = await response.json()
const mediaUploadFormData = new FormData()
for (const [key, value] of Object.entries(responseBody.formData)) {
mediaUploadFormData.append(key, value)
}
mediaUploadFormData.append('key', '${filename}')
mediaUploadFormData.append('Content-Type', file.file.type)
mediaUploadFormData.append('file', file.file, responseBody.filename)
console.log('Envoi image sur s3')
const s3Response = await fetch(`${S3_ENDPOINT}/${S3_BUCKET}/`, {
method: 'POST',
body: mediaUploadFormData
}).catch((e) => {
console.log('Erreur envoi S3: ' + e)
formError('Une erreur est survenue pendant l\'envoi d\'un média : ' + e)
})
if (!s3Response)
return
if (!s3Response.ok) {
console.log('Envoi media S3 failed: ' + s3Response.statusText + '\n\n' + s3Response.body)
formError('Une erreur est survenue pendant l\'envoi d\'un média : ' + s3Response.statusText)
return
}
assets.push(responseBody.id)
}
const response = await fetch(API_BASE_URL + '/admin/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-admin-token': authStore.adminToken
},
body: JSON.stringify({
description: values.description,
latitude: values.latitude,
longitude: values.longitude,
city: values.city,
country: values.country,
assets: assets
})
}).catch((e) => {
console.log('Erreur envoi post : ' + e)
formError('Une erreur est survenue pendant l\'envoi du post : ' + e)
})
if (!response)
return
if (!response.ok) {
console.log('POST post API failed: ' + response.statusText + '\n\n' + response.body)
formError('Une erreur est survenue lors de l\'envoi du poste : ' + response.statusText)
return
throw e
}
formStatus.value.sending = false
@ -179,31 +103,17 @@ function mediaReorder(index, diff) {
selectedFiles.value[index + diff] = tmp
}
function getCityAndCountry() {
function updateCityAndCountry() {
const lat = latitudeInput.value.value
const lon = longitudeInput.value.value
if (!lat || !lon)
return
fetch(`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=jsonv2`)
.then((resp) => resp.json()).then((resp) => {
const cityFieldOrder = ['city', 'town', 'borough', 'village', 'suburb', 'municipality', 'county', 'state']
let found = false
for (const field of cityFieldOrder) {
if (Object.hasOwn(resp.address, field)) {
found = true
form.setFieldValue('city', resp.address[field])
break
}
}
if (!found) {
form.setFieldValue('city', 'endroit perdu')
}
form.setFieldValue('country', resp.address.country)
if (!lat || !lon) return
getCityAndCountry(lat, lon).then((cityAndCountry) => {
form.setFieldValue('city', cityAndCountry[0])
form.setFieldValue('country', cityAndCountry[1])
})
}
</script>
<template>
@ -273,24 +183,34 @@ function getCityAndCountry() {
</FormControl>
</FormItem>
</FormField>
<Button class="place-self-end" @click="getCityAndCountry">
<Button class="place-self-end" @click="updateCityAndCountry">
<RefreshCcw />
</Button>
</div>
</form>
<form id="assets-form" class="mt-6">
<Label for="medias">Medias</Label>
<Input id="medias" type="file" accept="image/*,video/*" multiple @change="onFilesSelected" />
<Input
id="medias"
type="file"
accept="image/*,video/*"
multiple
@change="onFilesSelected"
/>
</form>
<Carousel
class="w-full mt-10"
:opts="{
align: 'start',
}"
align: 'start'
}"
v-if="selectedFiles.length > 0"
>
<CarouselContent>
<CarouselItem v-for="(file, index) in selectedFiles" :key="index" class="md:basis-1/2 lg:basis-1/3">
<CarouselItem
v-for="(file, index) in selectedFiles"
:key="index"
class="md:basis-1/2 lg:basis-1/3"
>
<div class="flex flex-col">
<Card>
<CardContent class="flex aspect-square items-center justify-center p-6">
@ -320,5 +240,4 @@ function getCityAndCountry() {
</div>
</template>
<style scoped>
</style>
<style scoped></style>