Riyyi
4 weeks ago
14 changed files with 234 additions and 24 deletions
@ -0,0 +1,7 @@ |
|||||||
|
/*----------------------------------------*/ |
||||||
|
/* General */ |
||||||
|
|
||||||
|
body { |
||||||
|
font-family: "Segoe UI", "DejaVu Sans", sans-serif; |
||||||
|
scroll-behavior: smooth; |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
<template> |
||||||
|
adasda |
||||||
|
<Column field="title"> |
||||||
|
<template #header> |
||||||
|
<span @click="toggleSorting('title')" class="p-datatable-column-title">Title |
||||||
|
<span :class="['pi', sorting.title === 'asc' ? 'pi-arrow-circle-down' : 'pi-arrow-circle-up']"></span> |
||||||
|
</span> |
||||||
|
</template> |
||||||
|
</Column> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
const sorting = defineModel<Record<string, string>>({ required: true }); |
||||||
|
|
||||||
|
function toggleSorting(key: string) { |
||||||
|
sorting.value[key] = sorting.value[key] === 'asc' ? 'desc' : 'asc'; |
||||||
|
}; |
||||||
|
</script> |
@ -0,0 +1,59 @@ |
|||||||
|
<template> |
||||||
|
<Form v-slot="$form" ref="formRef" :initialValues :resolver @submit="onFormSubmit" |
||||||
|
class="flex flex-col gap-4 w-full sm:w-56"> |
||||||
|
<!-- {{ $form }} --> |
||||||
|
<div class="flex flex-col gap-1"> |
||||||
|
<InputText @input="initial = false;" v-model="formData.title" name="title" type="text" placeholder="Title" |
||||||
|
autocomplete="off" fluid /> |
||||||
|
<Message v-if="$form.title?.invalid" severity="error" size="small" variant="simple"> |
||||||
|
{{ $form.title.error?.message }} |
||||||
|
</Message> |
||||||
|
</div> |
||||||
|
<Button :disabled="initial || !$form.valid" class="fr" type="submit" severity="secondary" label="Submit" /> |
||||||
|
</Form> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { useTodoStore } from "@/stores/todoStore"; |
||||||
|
import { todoSchema } from "@/schemas/todo"; |
||||||
|
import { zodResolver } from '@primevue/forms/resolvers/zod'; |
||||||
|
import { v4 as uuidv4 } from "uuid"; |
||||||
|
|
||||||
|
import { type FormSubmitEvent } from "@primevue/forms/form"; |
||||||
|
|
||||||
|
const store = useTodoStore(); |
||||||
|
const toast = useToast(); |
||||||
|
const resolver = zodResolver(todoSchema); |
||||||
|
|
||||||
|
const initial = ref(true); // makes submit button disabled |
||||||
|
const initialValues = ref({ |
||||||
|
title: "" |
||||||
|
}); |
||||||
|
const formRef = ref<HTMLElement | null>(null); |
||||||
|
const formData = ref({ ...initialValues.value }); // copy data from initialValues |
||||||
|
|
||||||
|
async function onFormSubmit(e: FormSubmitEvent) { |
||||||
|
if (e.valid) { |
||||||
|
toast.add({ severity: "success", summary: "Todo added", life: 3000 }); |
||||||
|
|
||||||
|
store.todos.push({ |
||||||
|
id: uuidv4(), |
||||||
|
title: e.values?.title || e.states?.title.value |
||||||
|
}); |
||||||
|
|
||||||
|
// Reset the form |
||||||
|
initial.value = true; |
||||||
|
formData.value = { ...initialValues.value }; // copy data from initialValues |
||||||
|
} |
||||||
|
else { |
||||||
|
toast.add({ severity: "error", summary: "Invalid request", life: 3000 }); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped> |
||||||
|
.fr { |
||||||
|
float: right; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,87 @@ |
|||||||
|
<template> |
||||||
|
<div class="card"> |
||||||
|
<ConfirmDialog></ConfirmDialog> |
||||||
|
<DataTable :value="computedTodos" tableStyle="min-width: 50rem" @sort="onSort" sortMode="multiple" removableSort> |
||||||
|
<Column field="number" header="#"></Column> |
||||||
|
<Column field="id" header="ID" sortable filterField="id" showFilterMenu filter="true"></Column> |
||||||
|
<Column field="title" header="Title" sortable filterField="title" showFilterMenu filter="true"></Column> |
||||||
|
<Column header="Modifier"> |
||||||
|
<template #body="slotProps"> |
||||||
|
<a @click="removeTodo(slotProps.data.id)"> |
||||||
|
<span class="pi pi-trash" style="color: var(--p-red-600);"></span> |
||||||
|
</a> |
||||||
|
</template> |
||||||
|
</Column> |
||||||
|
</DataTable> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { useConfirm } from "primevue/useconfirm"; |
||||||
|
import { useToast } from "primevue/usetoast"; |
||||||
|
import { useTodoStore } from "@/stores/todoStore"; |
||||||
|
|
||||||
|
import type { Todo } from "@/schemas/todo"; |
||||||
|
|
||||||
|
const confirm = useConfirm(); |
||||||
|
const store = useTodoStore(); |
||||||
|
const toast = useToast(); |
||||||
|
|
||||||
|
const onSort = (event: any) => { |
||||||
|
console.log(event); |
||||||
|
}; |
||||||
|
|
||||||
|
const sorting = ref<Record<string, string>>({ |
||||||
|
id: "asc", |
||||||
|
title: "asc", |
||||||
|
}); |
||||||
|
|
||||||
|
function toggleSorting(key: string) { |
||||||
|
sorting.value[key] = sorting.value[key] === 'asc' ? 'desc' : 'asc'; |
||||||
|
}; |
||||||
|
|
||||||
|
function sortTodos(): Todo[] { |
||||||
|
let todos: Todo[] = JSON.parse(JSON.stringify(store.todos)); // deep copy |
||||||
|
|
||||||
|
// Number |
||||||
|
|
||||||
|
// ID |
||||||
|
|
||||||
|
// Title |
||||||
|
todos = (sorting.value.title === "desc") |
||||||
|
? todos.sort((a, b) => b.title.localeCompare(a.title)) |
||||||
|
: todos.sort((a, b) => a.title.localeCompare(b.title)); |
||||||
|
|
||||||
|
return todos; |
||||||
|
} |
||||||
|
|
||||||
|
const computedTodos = computed(() => { |
||||||
|
return sortTodos().map((todo, index) => ({ |
||||||
|
number: index + 1, |
||||||
|
...todo |
||||||
|
})); |
||||||
|
}); |
||||||
|
|
||||||
|
const removeTodo = (id: String) => { |
||||||
|
confirm.require({ |
||||||
|
message: "Do you want to delete this todo?", |
||||||
|
header: "Confirmation", |
||||||
|
icon: "pi pi-info-circle", |
||||||
|
rejectLabel: "Cancel", |
||||||
|
rejectProps: { |
||||||
|
label: "Cancel", |
||||||
|
severity: "secondary", |
||||||
|
outlined: true |
||||||
|
}, |
||||||
|
acceptProps: { |
||||||
|
label: "Delete", |
||||||
|
severity: "danger" |
||||||
|
}, |
||||||
|
accept: () => { |
||||||
|
toast.add({ severity: "info", summary: "Confirmed", detail: "Todo deleted", life: 3000 }); |
||||||
|
store.todos = store.todos.filter(todo => todo.id !== id); |
||||||
|
}, |
||||||
|
reject: () => {} |
||||||
|
}); |
||||||
|
}; |
||||||
|
</script> |
@ -1,24 +1,18 @@ |
|||||||
<template> |
<template> |
||||||
<div class="card"> |
<TodoBrowse /> |
||||||
<DataTable :value="todos" tableStyle="min-width: 50rem"> |
<br> |
||||||
<Column field="number" header="#"></Column> |
<TodoAdd /> |
||||||
<Column field="id" header="ID"></Column> |
<br> |
||||||
<Column field="title" header="Title"></Column> |
<Button @click="showToast()" type="button">Toast</Button> |
||||||
<Column field="modifier" header="Modifier"></Column> |
|
||||||
</DataTable> |
|
||||||
</div> |
|
||||||
</template> |
</template> |
||||||
|
|
||||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||||
import { ref, onMounted } from 'vue'; |
import { useToast } from "primevue/usetoast"; |
||||||
// import { ProductService } from '@/service/ProductService'; |
|
||||||
|
|
||||||
onMounted(() => { |
const toast = useToast(); |
||||||
todos.value = [ |
|
||||||
{ number: "1", id: "toby", title: "Do stuff..", modifier: "hehe"} |
|
||||||
] |
|
||||||
}); |
|
||||||
|
|
||||||
const todos = ref(); |
async function showToast() { |
||||||
|
toast.add({ severity: "success", summary: "This is a toast", detail: "Wow!", life: 3000 }); |
||||||
|
} |
||||||
|
|
||||||
</script> |
</script> |
||||||
|
@ -0,0 +1,8 @@ |
|||||||
|
import { z } from "zod"; |
||||||
|
|
||||||
|
export const todoSchema = z.object({ |
||||||
|
id: z.optional(z.string().uuid()), |
||||||
|
title: z.string().min(1, "Title can't be empty"), |
||||||
|
}); |
||||||
|
|
||||||
|
export type Todo = z.infer<typeof todoSchema>; |
@ -0,0 +1,15 @@ |
|||||||
|
import { defineStore } from "pinia" |
||||||
|
import type { Todo } from "@/schemas/todo" |
||||||
|
|
||||||
|
export const useTodoStore = defineStore("todo", () => { |
||||||
|
|
||||||
|
const todos = ref<Todo[]>([ |
||||||
|
{ id: "d8681644-74d0-4a30-90db-06baa277d0a0", title: "laundry" }, |
||||||
|
{ id: "03c5bf55-f528-43a2-89a1-1a1afb0fa4f6", title: "feed pet" }, |
||||||
|
{ id: "356cd252-bef8-4a1c-ba81-5a68d89df56e", title: "run" } |
||||||
|
]); |
||||||
|
|
||||||
|
return { todos } |
||||||
|
}, { |
||||||
|
persist: process.env.NODE_ENV === 'development' ? true : false, |
||||||
|
}) |
Loading…
Reference in new issue