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:
parent
2647ac244d
commit
efde8738a8
23 changed files with 803 additions and 343 deletions
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue