some refactoring

Signed-off-by: Benny Samir Hierl <bennysamir@posteo.de>
This commit is contained in:
Benny Samir Hierl 2022-02-16 21:13:22 +01:00
parent a9badaf6f1
commit adf6014959
5 changed files with 161 additions and 165 deletions

View file

@ -0,0 +1,124 @@
<template>
<Form
@submit="onSubmit"
:validation-schema="schema"
v-slot="{ meta }"
class="w-full flex-col"
>
<InputText
name="title"
type="text"
:value="wishlist.title"
:label="t('components.wishlist-header.main.form.title.label')"
/>
<InputCheckbox
name="public"
:value="wishlist.public"
:label="t('components.wishlist-header.main.form.public.label')"
/>
<InputTextArea
name="description"
type="text"
:value="wishlist.description"
height-class="h-20"
:label="t('components.wishlist-header.main.form.description.label')"
/>
<InputText
name="imageSrc"
type="text"
:value="wishlist.imageSrc"
:label="t('components.wishlist-header.main.form.image-src.label')"
/>
<InputFile
name="imageFile"
:label="t('components.wishlist-header.main.form.image-file.label')"
/>
<InputText
name="slugUrlText"
type="text"
:value="wishlist.slugUrlText"
:label="t('components.wishlist-header.main.form.slug-text.label')"
/>
<ButtonBase
class="h-12 w-full"
mode="primary"
:disabled="!meta.valid"
:icon="IconSave"
>{{ t('components.wishlist-header.main.form.submit.text') }}</ButtonBase
>
</Form>
</template>
<script setup lang="ts">
import { Wishlist } from '@/types'
import { PropType } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { Form } from 'vee-validate'
import { object, string, boolean } from 'yup'
import { useToast } from 'vue-toastification'
import {
ButtonBase,
InputText,
InputFile,
InputCheckbox,
InputTextArea,
} from '@/components'
import { IconSave } from '@/components/icons'
import { useWishlistStore } from '@/composables'
defineProps({
wishlist: {
type: Object as PropType<Wishlist>,
requried: true,
},
})
const router = useRouter()
const toast = useToast()
const { update } = useWishlistStore()
const { t } = useI18n()
const schema = object().shape(
{
title: string().required(
t('components.wishlist-header.main.form.title.error-requried')
),
public: boolean(),
description: string().max(
300,
t('components.wishlist-header.main.form.description.error-max')
),
slugUrlText: string().required(
t('components.wishlist-header.main.form.slug-text.error-requried')
),
imageSrc: string().when('imageFile', {
is: (imageFile: string) => !imageFile || imageFile.length === 0,
then: string().required(
t('components.wishlist-header.main.form.image-src.error-requried')
),
}),
imageFile: string().when('imageSrc', {
is: (imageSrc: string) => !imageSrc || imageSrc.length === 0,
then: string().required(
t('components.wishlist-header.main.form.image-file.error-requried')
),
}),
},
//@ts-expect-error ...
['imageSrc', 'imageFile']
)
const onSubmit = async (values: any): Promise<void> => {
try {
values.imageSrc = values.imageFile || values.imageSrc
await update(values)
toast.success(t('common.wishlist.saved.text'))
router.push(`/${values.slugUrlText}`)
} catch (error) {
toast.error(t('common.wishlist.saving-failed.text'))
}
}
</script>

View file

@ -1,141 +0,0 @@
<template>
<div
class="flex flex-col items-center space-x-0 space-y-2 md:flex-row md:space-x-6 md:space-y-0"
v-if="modelValue !== undefined"
>
<ImageTile :image-src="modelValue.imageSrc" class="shrink-0"></ImageTile>
<div v-if="!editModeIsActive">
<h1 class="mb-2 text-center text-2xl font-bold md:text-left">
{{ modelValue.title }}
</h1>
<p class="text-lg">
{{ modelValue.description }}
</p>
</div>
<Form
v-else
@submit="onSubmit"
:validation-schema="schema"
v-slot="{ meta }"
class="w-full flex-col"
>
<InputText
name="title"
type="text"
:value="modelValue.title"
:label="t('components.wishlist-header.main.form.title.label')"
/>
<InputCheckbox
name="public"
:value="modelValue.public"
:label="t('components.wishlist-header.main.form.public.label')"
/>
<InputTextArea
name="description"
type="text"
:value="modelValue.description"
height-class="h-20"
:label="t('components.wishlist-header.main.form.description.label')"
/>
<InputText
name="imageSrc"
type="text"
:value="modelValue.imageSrc"
:label="t('components.wishlist-header.main.form.image-src.label')"
/>
<InputFile
name="imageFile"
:label="t('components.wishlist-header.main.form.image-file.label')"
/>
<InputText
name="slugUrlText"
type="text"
:value="modelValue.slugUrlText"
:label="t('components.wishlist-header.main.form.slug-text.label')"
/>
<ButtonBase
class="h-12 w-full"
mode="primary"
:disabled="!meta.valid"
:icon="IconSave"
>{{ t('components.wishlist-header.main.form.submit.text') }}</ButtonBase
>
</Form>
</div>
</template>
<script setup lang="ts">
import { Wishlist } from '@/types'
import { PropType } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { Form } from 'vee-validate'
import { object, string, boolean } from 'yup'
import { useToast } from 'vue-toastification'
import {
ButtonBase,
ImageTile,
InputText,
InputFile,
InputCheckbox,
InputTextArea,
} from '@/components'
import { IconSave } from '@/components/icons'
import { useEditMode, useWishlistStore } from '@/composables'
defineProps({
modelValue: {
type: Object as PropType<Wishlist>,
requried: true,
},
})
const router = useRouter()
const toast = useToast()
const { isActive: editModeIsActive } = useEditMode()
const { update } = useWishlistStore()
const { t } = useI18n()
const schema = object().shape(
{
title: string().required(
t('components.wishlist-header.main.form.title.error-requried')
),
public: boolean(),
description: string().max(
300,
t('components.wishlist-header.main.form.description.error-max')
),
slugUrlText: string().required(
t('components.wishlist-header.main.form.slug-text.error-requried')
),
imageSrc: string().when('imageFile', {
is: (imageFile: string) => !imageFile || imageFile.length === 0,
then: string().required(
t('components.wishlist-header.main.form.image-src.error-requried')
),
}),
imageFile: string().when('imageSrc', {
is: (imageSrc: string) => !imageSrc || imageSrc.length === 0,
then: string().required(
t('components.wishlist-header.main.form.image-file.error-requried')
),
}),
},
//@ts-expect-error ...
['imageSrc', 'imageFile']
)
const onSubmit = async (values: any): Promise<void> => {
try {
values.imageSrc = values.imageFile || values.imageSrc
await update(values)
toast.success(t('common.wishlist.saved.text'))
router.push(`/${values.slugUrlText}`)
} catch (error) {
toast.error(t('common.wishlist.saving-failed.text'))
}
}
</script>

View file

@ -4,11 +4,9 @@ import IconLink from './icons/IconLink.vue'
import ImagePreview from './ImagePreview.vue' import ImagePreview from './ImagePreview.vue'
import { ButtonBase } from './' import { ButtonBase } from './'
import IconCart from './icons/IconCart.vue' import IconCart from './icons/IconCart.vue'
import { WishlistItem } from '@/types'
defineProps<{ defineProps<{
title: string item: WishlistItem
image: string
url?: string
description: string
}>() }>()
const { t } = useI18n() const { t } = useI18n()
</script> </script>
@ -19,15 +17,15 @@ const { t } = useI18n()
> >
<ImagePreview <ImagePreview
class="max-h-44 flex-shrink-0 flex-grow-0 object-cover sm:aspect-[3/2]" class="max-h-44 flex-shrink-0 flex-grow-0 object-cover sm:aspect-[3/2]"
:src="image" :src="item.imageSrc"
:alt="title" :alt="item.title"
/> />
<div class="flex flex-col justify-between p-2"> <div class="flex flex-col justify-between p-2">
<div> <div>
<h1 class="mb-1 text-lg font-bold">{{ title }}</h1> <h1 class="mb-1 text-lg font-bold">{{ item.title }}</h1>
<p class="text-sm sm:line-clamp-3"> <p class="text-sm sm:line-clamp-3">
{{ description }} {{ item.description }}
</p> </p>
</div> </div>
<div class="flex flex-row items-baseline space-x-2"> <div class="flex flex-row items-baseline space-x-2">
@ -38,8 +36,8 @@ const { t } = useI18n()
>{{ t('components.wishlist-item.bought-button.text') }}</ButtonBase >{{ t('components.wishlist-item.bought-button.text') }}</ButtonBase
> >
<a <a
v-if="url" v-if="item.url"
:href="url" :href="item.url"
target="_blank" target="_blank"
rel="noopener" rel="noopener"
class="mt-1 flex w-fit flex-row items-center text-sm text-stone-500 dark:text-white/60" class="mt-1 flex w-fit flex-row items-center text-sm text-stone-500 dark:text-white/60"

View file

@ -7,5 +7,5 @@ export { default as InputText } from './InputText.vue'
export { default as InputFile } from './InputFile.vue' export { default as InputFile } from './InputFile.vue'
export { default as InputTextArea } from './InputTextArea.vue' export { default as InputTextArea } from './InputTextArea.vue'
export { default as Modal } from './Modal.vue' export { default as Modal } from './Modal.vue'
export { default as WishlistHeader } from './WishlistHeader.vue' export { default as FormWishlist } from './FormWishlist.vue'
export { default as WishlistItem } from './WishlistItem.vue' export { default as WishlistItem } from './WishlistItem.vue'

View file

@ -2,14 +2,14 @@
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { WishlistItem as WishlistItemType } from '@/types' import { WishlistItem as WishlistItemType } from '@/types'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { useWishlistStore, useModal } from '@/composables' import { useWishlistStore, useModal, useEditMode } from '@/composables'
import WishlistItem from '@/components/WishlistItem.vue' import { FormWishlist, ImageTile, WishlistItem } from '@/components'
import WishlistHeader from '@/components/WishlistHeader.vue'
import { IconNoGift } from '../components/icons' import { IconNoGift } from '../components/icons'
const route = useRoute() const route = useRoute()
const modal = useModal() const modal = useModal()
const { t } = useI18n() const { t } = useI18n()
const { isActive: editModeIsActive } = useEditMode()
const { state, fetch, isReady, itemBought, filteredItems } = useWishlistStore() const { state, fetch, isReady, itemBought, filteredItems } = useWishlistStore()
await fetch(route.params.slug as string) await fetch(route.params.slug as string)
@ -29,20 +29,35 @@ const bought = async (item: WishlistItemType): Promise<void> => {
<template> <template>
<div v-if="isReady" class="h-full"> <div v-if="isReady" class="h-full">
<WishlistHeader v-model="state" /> <div
class="flex flex-col items-center space-x-0 space-y-2 md:flex-row md:space-x-6 md:space-y-0"
v-if="state !== undefined"
>
<ImageTile :image-src="state.imageSrc" class="shrink-0"></ImageTile>
<div v-if="!editModeIsActive">
<h1 class="mb-2 text-center text-2xl font-bold md:text-left">
{{ state.title }}
</h1>
<p class="text-lg">
{{ state.description }}
</p>
</div>
<FormWishlist v-else :wishlist="state" />
</div>
<div <div
v-if="filteredItems.length > 0" v-if="filteredItems.length > 0"
class="flex flex-col space-y-14 py-10 md:space-y-8" class="flex flex-col space-y-14 py-10 md:space-y-8"
> >
<WishlistItem <div v-for="(item, index) in filteredItems" :key="index">
v-for="(item, index) in filteredItems" <WishlistItem
:key="index" :item="item"
:title="item.title" :title="item.title"
:url="item.url" :url="item.url"
:image="item.imageSrc" :image="item.imageSrc"
:description="item.description" :description="item.description"
@bought="bought(item)" @bought="bought(item)"
/> />
</div>
</div> </div>
<div v-else class="flex h-1/2 w-full justify-center"> <div v-else class="flex h-1/2 w-full justify-center">
<div <div