add wishlist item page added for bookmark adding

Signed-off-by: Benny Samir Hierl <bennysamir@posteo.de>
This commit is contained in:
Benny Samir Hierl 2022-02-20 12:29:20 +01:00
parent f9147e9751
commit 2ee5c03935
8 changed files with 155 additions and 9 deletions

4
components.d.ts vendored
View file

@ -28,8 +28,6 @@ declare module 'vue' {
IconToggleOn: typeof import('./src/components/icons/IconToggleOn.vue')['default']
ImagePreview: typeof import('./src/components/ImagePreview.vue')['default']
ImageTile: typeof import('./src/components/ImageTile.vue')['default']
'ImageTile copy': typeof import('./src/components/ImageTile copy.vue')['default']
ImageTilePlaceholder: typeof import('./src/components/ImageTilePlaceholder.vue')['default']
InputFile: typeof import('./src/components/InputFile.vue')['default']
InputText: typeof import('./src/components/InputText.vue')['default']
InputTextArea: typeof import('./src/components/InputTextArea.vue')['default']
@ -39,4 +37,4 @@ declare module 'vue' {
}
}
export {}
export { }

View file

@ -24,7 +24,7 @@ export const fetchOpenGraph = <RouteOptions>{
properties: {
title: { type: 'string' },
description: { type: 'string' },
image: { type: 'string' },
imageSrc: { type: 'string' },
},
},
},
@ -42,7 +42,7 @@ export const fetchOpenGraph = <RouteOptions>{
reply.send({
title: result.ogTitle || '',
description: result.ogDescription || '',
image,
imageSrc: image,
})
}
},

View file

@ -47,8 +47,11 @@ const deleteWishlist = async (): Promise<void> => {
}
}
const createItem = async (values: WishlistItem): Promise<void> => {
const id = state.value?.id
const createItem = async (
values: WishlistItem,
wishlistId?: string
): Promise<void> => {
const id = wishlistId || state.value?.id
const payload = {
...values,
}

View file

@ -62,6 +62,17 @@
"text": "Erstelle eine Wunschliste"
}
},
"create-wishlist-item-view": {
"title": {
"text": "Eintrag hinzufügen"
},
"loading": {
"text": "Lade Daten der übermittelten URL"
},
"headline-wishlist-selection": {
"text": "Zu welcher Wunschliste möchten Sie etwas hinzufügen?"
}
},
"detail-view": {
"main": {
"empty-list": {

View file

@ -54,6 +54,17 @@
}
}
},
"create-wishlist-item-view": {
"title": {
"text": "Add item"
},
"loading": {
"text": "Loading data from provided URL"
},
"headline-wishlist-selection": {
"text": "To which wish list would you like to add the new item?"
}
},
"create-wishlist-view": {
"title": {
"text": "Create a wishlist"

View file

@ -2,7 +2,10 @@ import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '@/views/HomeView.vue'
import LoginView from '@/views/LoginView.vue'
import CreateWishlistView from '@/views/CreateWishlistView.vue'
import AddWishlistItemView from '@/views/AddWishlistItemView.vue'
import DetailView from '@/views/DetailView.vue'
import { useAuth } from '@/composables'
const { isAuthenticated } = useAuth()
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
@ -11,28 +14,45 @@ const router = createRouter({
path: '/',
name: 'home',
component: HomeView,
meta: { requiresAuth: false },
},
{
path: '/login',
name: 'login',
component: LoginView,
meta: { requiresAuth: false },
},
{
path: '/create-wishlist',
name: 'create-wishlist',
component: CreateWishlistView,
meta: { requiresAuth: true },
},
{
path: '/add-wishlist-item',
name: 'add-wishlist--item',
component: AddWishlistItemView,
meta: { requiresAuth: true },
},
{
path: '/:slug',
name: 'detail',
component: DetailView,
meta: { requiresAuth: false },
},
{
name: 'notFound',
path: '/:pathMatch(.*)*',
component: () => import('@/views/NotFoundView.vue'),
meta: { requiresAuth: false },
},
],
})
router.beforeEach((to, from) => {
if (!isAuthenticated.value && to.meta.requiresAuth === true) {
return { name: 'login' }
}
})
export default router

View file

@ -1,11 +1,11 @@
export interface WishlistItem {
id: number
id?: number
title: string
url: string
imageSrc: string
description: string
bought: boolean
wishlistId: boolean
wishlistId?: boolean
}
export interface Wishlist {
id?: string

View file

@ -0,0 +1,103 @@
<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import { Wishlist, WishlistItem } from '@/types'
import { useRoute, useRouter } from 'vue-router'
import { useWishlistsStore, useWishlistStore } from '@/composables'
import { useToast } from 'vue-toastification'
import { useFetch } from '@/composables/useFetch'
import { syncRef, useTitle, watchOnce } from '@vueuse/core'
import { Ref, ref } from 'vue'
const route = useRoute()
const router = useRouter()
const { t } = useI18n()
const toast = useToast()
const isFinished = ref(true)
const selectedWishlist: Ref<Wishlist | undefined> = ref()
const prefillData = ref({
title: '',
description: '',
imageSrc: '',
url: '',
bought: false,
})
const { createItem } = useWishlistStore()
const {
state: wishlists,
isFinished: loadWishlistsFinished,
fetch,
} = useWishlistsStore()
fetch()
if (route.query.url) {
prefillData.value.url = route.query.url as string
const { data: opData, isFinished: opDataLoaded } = useFetch(
`/utils/fetch-open-graph?url=${route.query.url}`
).json()
syncRef(opDataLoaded, isFinished)
watchOnce(opData, () => {
prefillData.value = {
...prefillData.value,
...opData.value,
}
})
}
useTitle(t('pages.create-wishlist-item-view.title.text'))
const handleCreateItem = async (values: WishlistItem): Promise<void> => {
try {
await createItem(values, selectedWishlist?.value?.id)
toast.success(t('common.saved.text'))
router.push(`/${selectedWishlist?.value?.slugUrlText}`)
} catch (error) {
console.error(error)
toast.error(t('common.saving-failed.text'))
}
}
</script>
<template>
<div class="h-full">
<div
v-if="!isFinished || !loadWishlistsFinished"
class="flex h-1/2 w-full flex-col justify-center"
>
<div
class="m-20 flex flex-row content-center items-center justify-center space-x-2"
>
<IconSpinner class="h-4 w-4" />
<span> {{ t('pages.create-wishlist-item-view.loading.text') }} </span>
</div>
</div>
<div v-else-if="loadWishlistsFinished && selectedWishlist === undefined">
<h1 class="text-center text-xl font-bold">
{{
t('pages.create-wishlist-item-view.headline-wishlist-selection.text')
}}
</h1>
<div
class="m-8 flex flex-row flex-wrap content-center items-center justify-center sm:space-x-2"
>
<div
v-for="item in wishlists"
:key="item.id"
@click="() => (selectedWishlist = item)"
class="cursor-pointer"
>
<ImageTile
:title="item.title"
:image-src="item.imageSrc"
class="m-4"
/>
</div>
</div>
</div>
<FormWishlistItem :item="prefillData" v-else @create="handleCreateItem" />
</div>
</template>