feat: category creation

This commit is contained in:
Florian Sylvain
2024-10-10 22:26:54 +02:00
parent 81bc46ebfa
commit ec9bc1bb4b
7 changed files with 121 additions and 39 deletions
+5 -27
View File
@@ -1,31 +1,9 @@
<script setup lang="ts">
import { useCategoriesStore } from '@/stores/categories'
import { onMounted, ref, type Ref } from 'vue'
import type { Category } from '@/composables/category'
interface Category {
categories: {
id: number
name: string
user_id: number
}[]
pagination: {
skip: number
take: number
}
links: {
next: string
prev: string
}
total: number
}
const categoriesStore = useCategoriesStore()
const fetchedCategories: Ref<Category | undefined> = ref()
onMounted(async () => {
const categoriesPromise = await categoriesStore.getCategories()
fetchedCategories.value = await categoriesPromise.json()
})
const props = defineProps<{
fetchedCategories: Category | undefined
}>()
</script>
<template>
@@ -34,7 +12,7 @@ onMounted(async () => {
{ title: 'Name', key: 'name', sortable: true },
{ title: 'Actions', key: 'actions', align: 'end', sortable: false }
]"
:items="fetchedCategories?.categories"
:items="props.fetchedCategories?.categories"
>
<template
v-slot:[`item.actions`]="{
+68
View File
@@ -0,0 +1,68 @@
<script setup lang="ts">
import { useCategoriesStore } from '@/stores/categories'
import { ref, type Ref } from 'vue'
const emit = defineEmits<{
categoryCreated: [id: number]
}>()
const dialog: Ref<boolean> = ref(false)
const valid: Ref<boolean> = ref(false)
const name: Ref<string> = ref('')
const nameRules: Ref<Array<(v: string) => boolean | string>> = ref([
(value) => {
if (value.length > 0 && value.length <= 50) return true
return `Name length should be below 50 characters. (currently: ${value.length})`
}
])
const categoriesStore = useCategoriesStore()
async function onSubmit(): Promise<void> {
const createdCategoryPromise = await categoriesStore.postCategory(name.value)
const createdCategory: { id: number } = await createdCategoryPromise.json()
emit('categoryCreated', createdCategory.id)
dialog.value = false
}
</script>
<template>
<VDialog v-model="dialog" max-width="500">
<template v-slot:activator="{ props: activatorProps }">
<VBtn
prepend-icon="mdi-plus"
text="Create Category"
color="primary"
variant="flat"
v-bind="activatorProps"
></VBtn>
</template>
<VCard prepend-icon="mdi-plus" title="Create Category">
<VForm v-model="valid" @submit.prevent="onSubmit">
<VCardText>
<VText-field
v-model="name"
:rules="nameRules"
label="Name*"
variant="outlined"
hide-details="auto"
required
></VText-field>
</VCardText>
<VDivider></VDivider>
<VCardActions>
<VSpacer></VSpacer>
<VBtn color="primary" text="Close" variant="outlined" @click="dialog = false"></VBtn>
<VBtn
color="primary"
text="Create"
variant="flat"
type="submit"
:disabled="!valid"
></VBtn>
</VCardActions>
</VForm>
</VCard>
</VDialog>
</template>
+16
View File
@@ -0,0 +1,16 @@
export interface Category {
categories: {
id: number
name: string
user_id: number
}[]
pagination: {
skip: number
take: number
}
links: {
next: string
prev: string
}
total: number
}
+4 -6
View File
@@ -13,10 +13,9 @@ export const useAuthStore = defineStore('auth', () => {
const postLogin = async (credentials: LoginFields): Promise<Response> => {
const loginPromise = await fetch(`${api.url}/session/login`, {
headers: { 'Content-Type': 'application/json' },
...api.options,
method: 'POST',
body: JSON.stringify(credentials),
credentials: 'include'
body: JSON.stringify(credentials)
})
cookie.setCookie('loggedIn', new Date(new Date().getTime() + 7200000).toString())
return loginPromise
@@ -24,9 +23,8 @@ export const useAuthStore = defineStore('auth', () => {
const postLogout = async (): Promise<Response> => {
return await fetch(`${api.url}/session/logout`, {
headers: { 'Content-Type': 'application/json' },
method: 'POST',
credentials: 'include'
...api.options,
method: 'POST'
})
}
+10 -2
View File
@@ -4,9 +4,17 @@ import { defineStore } from 'pinia'
export const useCategoriesStore = defineStore('categories', () => {
const api = useApi()
const getCategories = async () => {
const getCategories = async (): Promise<Response> => {
return await fetch(`${api.url}/category`, api.options)
}
return { getCategories }
const postCategory = async (name: string): Promise<Response> => {
return await fetch(`${api.url}/category`, {
...api.options,
method: 'POST',
body: JSON.stringify({ name })
})
}
return { getCategories, postCategory }
})
+16 -2
View File
@@ -1,11 +1,25 @@
<script setup lang="ts">
import CategoriesTable from '@/components/CategoriesTable.vue'
import CategoryCreate from '@/components/CategoryCreate.vue'
import type { Category } from '@/composables/category'
import { useCategoriesStore } from '@/stores/categories'
import { onMounted, ref, type Ref } from 'vue'
const categoriesStore = useCategoriesStore()
const fetchedCategories: Ref<Category | undefined> = ref()
async function updateCategories() {
const categoriesPromise = await categoriesStore.getCategories()
fetchedCategories.value = await categoriesPromise.json()
}
onMounted(updateCategories)
</script>
<template>
<header class="d-flex align-center justify-space-between">
<h1 class="text-h3">Categories</h1>
<VBtn prepend-icon="mdi-plus" variant="flat" color="primary">Create category</VBtn>
<CategoryCreate @categoryCreated="updateCategories" />
</header>
<CategoriesTable />
<CategoriesTable :fetched-categories="fetchedCategories" />
</template>
+2 -2
View File
@@ -39,7 +39,7 @@ async function onSubmit(): Promise<void> {
<VTextField
v-model="email"
:rules="emailRules"
label="E-mail"
label="E-mail*"
type="email"
variant="outlined"
color="primary"
@@ -49,7 +49,7 @@ async function onSubmit(): Promise<void> {
<div class="d-flex flex-column">
<VTextField
v-model="password"
label="Password"
label="Password*"
type="password"
variant="outlined"
color="primary"