removing entries works extracted formular into component
This commit is contained in:
54
src/components/EntryForm.vue
Normal file
54
src/components/EntryForm.vue
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import * as z from 'zod'
|
||||||
|
import { toTypedSchema } from '@vee-validate/zod'
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Form, FormItem, FormLabel, FormField, FormControl, FormMessage, FormDescription } from '@/components/ui/form';
|
||||||
|
import { Button } from './ui/button';
|
||||||
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
submit: [value: CreateEntrySchema]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
action: 'create' | 'edit'
|
||||||
|
}>()
|
||||||
|
|
||||||
|
|
||||||
|
const createEntryZodSchema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
text: z.string().optional()
|
||||||
|
})
|
||||||
|
|
||||||
|
export type CreateEntrySchema = z.infer<typeof createEntryZodSchema>
|
||||||
|
|
||||||
|
const createEntrySchema = toTypedSchema(createEntryZodSchema)
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Form :validation-schema="createEntrySchema" @submit="(val) => emit('submit', val as CreateEntrySchema)">
|
||||||
|
<FormField v-slot="{ componentField }" name="name">
|
||||||
|
<FormItem>
|
||||||
|
<FormControl>
|
||||||
|
<Input placeholder="Name" v-bind="componentField" />
|
||||||
|
</FormControl>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
<FormField v-slot="{ componentField }" name="text">
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel></FormLabel>
|
||||||
|
<FormControl>
|
||||||
|
<Textarea placeholder="Text" v-bind="componentField" />
|
||||||
|
</FormControl>
|
||||||
|
<FormDescription />
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
</FormField>
|
||||||
|
<Button type="submit" class="w-full" v-if="props.action === 'create'">Create</Button>
|
||||||
|
<Button type="submit" class="w-full" v-else>Edit</Button>
|
||||||
|
</Form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Card, CardTitle, CardDescription } from '@/components/ui/card';
|
import { Card, CardTitle, CardDescription } from '@/components/ui/card';
|
||||||
import { entries, getDifferenceToToday } from '@/data/entries';
|
import { Entry, entries, getDifferenceToToday, save } from '@/data/entries';
|
||||||
import { ArrowBigLeft, MenuIcon, TrashIcon } from 'lucide-vue-next';
|
import { ArrowBigLeft, MenuIcon, TrashIcon } from 'lucide-vue-next';
|
||||||
import {
|
import {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
@@ -11,11 +11,26 @@ import {
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
import { toast } from 'vue-sonner';
|
||||||
|
|
||||||
const probs = defineProps<{ name: string }>()
|
const probs = defineProps<{ name: string }>()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const entry = ref(entries.value.find(entry => entry.name === probs.name))
|
const entry = ref(entries.value.find(entry => entry.name === probs.name))
|
||||||
|
|
||||||
|
|
||||||
|
function deleteEntry(entry: Entry) {
|
||||||
|
const index = entries.value.indexOf(entry)
|
||||||
|
|
||||||
|
if (index === undefined) {
|
||||||
|
toast('Deletion failed')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.value.splice(index, 1)
|
||||||
|
save()
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -41,12 +56,13 @@ const entry = ref(entries.value.find(entry => entry.name === probs.name))
|
|||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
|
|
||||||
<DropdownMenuContent class="mr-2">
|
<DropdownMenuContent class="mr-2">
|
||||||
<DropdownMenuItem>
|
<DropdownMenuItem @click="() => deleteEntry(entry)">
|
||||||
<TrashIcon color="#ef4444"/>
|
<TrashIcon color="#ef4444"/>
|
||||||
<span color="#ef4444">Delete</span>
|
<span color="#ef4444">Delete</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
|
|
||||||
</nav>
|
</nav>
|
||||||
<div id="content" class="w-full flex flex-col gap-5 items-center mt-20">
|
<div id="content" class="w-full flex flex-col gap-5 items-center mt-20">
|
||||||
<Button class="w-full">Edit</Button>
|
<Button class="w-full">Edit</Button>
|
||||||
|
|||||||
@@ -2,115 +2,83 @@
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Plus } from 'lucide-vue-next';
|
import { Plus } from 'lucide-vue-next';
|
||||||
import { entries, save } from '@/data/entries';
|
import { entries, save } from '@/data/entries';
|
||||||
import { Drawer, DrawerHeader, DrawerTitle, DrawerTrigger, DrawerContent, DrawerFooter, DrawerClose } from '@/components/ui/drawer';
|
import { Drawer, DrawerHeader, DrawerTitle, DrawerContent, DrawerClose } from '@/components/ui/drawer';
|
||||||
import { Form, FormItem, FormLabel, FormField, FormControl, FormMessage, FormDescription } from '@/components/ui/form';
|
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Input } from '@/components/ui/input';
|
|
||||||
import { Textarea } from '@/components/ui/textarea';
|
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
|
import EntryForm from '@/components/EntryForm.vue'
|
||||||
|
import { CreateEntrySchema } from '@/components/EntryForm.vue'
|
||||||
import { getDifferenceToToday } from '@/data/entries';
|
import { getDifferenceToToday } from '@/data/entries';
|
||||||
import { toTypedSchema } from '@vee-validate/zod';
|
|
||||||
import * as z from 'zod'
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { toast } from 'vue-sonner';
|
import { toast } from 'vue-sonner';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const createDrawerState = ref(false)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const createEntryZodSchema = z.object({
|
|
||||||
name: z.string(),
|
|
||||||
text: z.string().optional()
|
|
||||||
})
|
|
||||||
|
|
||||||
type CreateEntrySchema = z.infer<typeof createEntryZodSchema>
|
async function createEntry(value: CreateEntrySchema) {
|
||||||
|
if (entries.value.map(entry => entry.name).includes(value.name)) {
|
||||||
|
toast('Accident Entry allready exists', {
|
||||||
|
important: true,
|
||||||
|
description: 'please use a unique name'
|
||||||
|
})
|
||||||
|
|
||||||
const createEntrySchema = toTypedSchema(createEntryZodSchema)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.value.push({
|
||||||
|
last_reset: moment(),
|
||||||
|
name: value.name,
|
||||||
|
text: value.text && value.text.trim() !== ''
|
||||||
|
? value.text : undefined
|
||||||
|
})
|
||||||
|
|
||||||
function createEntry(value: CreateEntrySchema) {
|
save()
|
||||||
if (entries.value.map(entry => entry.name).includes(value.name)) {
|
createDrawerState.value = false
|
||||||
toast('Accident Entry allready exists', {
|
|
||||||
important: true,
|
|
||||||
description: 'please use a unique name'
|
|
||||||
})
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
entries.value.push({
|
|
||||||
last_reset: moment(),
|
|
||||||
name: value.name,
|
|
||||||
text: value.text && value.text.trim() !== ''
|
|
||||||
? value.text : undefined
|
|
||||||
})
|
|
||||||
|
|
||||||
save()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function openDetailWithName(name: string) {
|
function openDetailWithName(name: string) {
|
||||||
console.log('opening', name)
|
console.log('opening', name)
|
||||||
router.push({
|
router.push({
|
||||||
path: `${name}`,
|
path: `${name}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<ScrollArea class="w-full">
|
<ScrollArea class="w-full">
|
||||||
<div class="w-full flex justify-center flex-col items-center">
|
<div class="w-full flex justify-center flex-col items-center">
|
||||||
<header id="title" class="flex w-full h-56 justify-center items-center flex-row">Accident Board</header>
|
<header id="title" class="flex w-full h-56 justify-center items-center flex-row">Accident Board</header>
|
||||||
<main class="wrapper sm:w-3/4 w-11/12 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-4">
|
<main class="wrapper sm:w-3/4 w-11/12 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-5 gap-4">
|
||||||
<Button v-for="entry in entries" class="w-full p-10 flex flex-col items-center gap-2"
|
<Button v-for="entry in entries" class="w-full p-10 flex flex-col items-center gap-2"
|
||||||
@click="openDetailWithName(entry.name)">
|
@click="openDetailWithName(entry.name)">
|
||||||
<span>{{ entry.name }}</span>
|
<span>{{ entry.name }}</span>
|
||||||
<Badge variant="secondary">{{ getDifferenceToToday(entry.last_reset) }} days</Badge>
|
<Badge variant="secondary">{{ getDifferenceToToday(entry.last_reset) }} days</Badge>
|
||||||
</Button>
|
</Button>
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
|
|
||||||
<Drawer>
|
|
||||||
<DrawerTrigger as-child>
|
|
||||||
<div class="fixed bottom-0 w-full h-28 flex justify-center items-center">
|
|
||||||
<Button size="icon" class="h-20 sm:w-3/4 w-11/12">
|
|
||||||
<Plus />
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</DrawerTrigger>
|
|
||||||
|
|
||||||
<DrawerContent>
|
<div id="placeholder" class="h-32"></div>
|
||||||
<DrawerHeader>
|
|
||||||
<DrawerTitle>Create new Entry</DrawerTitle>
|
<div class="fixed bottom-0 w-full h-28 flex justify-center items-center shadow-2xl shadow-black bg-white">
|
||||||
</DrawerHeader>
|
<Button size="icon" class="h-20 sm:w-3/4 w-11/12" @click="createDrawerState = true">
|
||||||
<div id="content" class="p-5">
|
<Plus />
|
||||||
<Form :validation-schema="createEntrySchema" @submit="(val) => createEntry(val as CreateEntrySchema)">
|
</Button>
|
||||||
<FormField v-slot="{ componentField }" name="name">
|
</div>
|
||||||
<FormItem>
|
|
||||||
<FormControl>
|
<Drawer v-model:open="createDrawerState">
|
||||||
<Input placeholder="Name" v-bind="componentField" />
|
<DrawerContent>
|
||||||
</FormControl>
|
<DrawerHeader>
|
||||||
<FormMessage/>
|
<DrawerTitle>Create new Entry</DrawerTitle>
|
||||||
</FormItem>
|
</DrawerHeader>
|
||||||
</FormField>
|
<div id="content" class="p-5">
|
||||||
<FormField v-slot="{ componentField }" name="text">
|
<EntryForm action="create" @submit="(val) => createEntry(val)"> </EntryForm>
|
||||||
<FormItem>
|
</div>
|
||||||
<FormLabel></FormLabel>
|
</DrawerContent>
|
||||||
<FormControl>
|
</Drawer>
|
||||||
<Textarea placeholder="Text" v-bind="componentField" />
|
|
||||||
</FormControl>
|
|
||||||
<FormDescription />
|
|
||||||
<FormMessage />
|
|
||||||
</FormItem>
|
|
||||||
</FormField>
|
|
||||||
<DrawerFooter>
|
|
||||||
<DrawerClose>
|
|
||||||
<Button type="submit">Create</Button>
|
|
||||||
</DrawerClose>
|
|
||||||
</DrawerFooter>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</DrawerContent>
|
|
||||||
</Drawer>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
Reference in New Issue
Block a user