create permission crud
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { getCurrentInstance, onMounted, ref } from 'vue'
|
||||
import { Head } from '@inertiajs/inertia-vue3'
|
||||
import { Head, usePage } from '@inertiajs/inertia-vue3'
|
||||
import Toggler from '@/Components/DashboardLayout/SidebarToggler.vue'
|
||||
import TopbarDropdown from '@/Components/DashboardLayout/TopbarDropdown.vue'
|
||||
import Sidebar from '@/Components/DashboardLayout/Sidebar.vue';
|
||||
@@ -15,6 +15,17 @@ const open = ref(window.innerWidth > 669)
|
||||
onMounted(() => window.addEventListener('resize', () => open.value = window.innerWidth > 669))
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: all 300ms ease-in-out;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.fade-enter-from, .fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="flex bg-gray-200 dark:bg-gray-900 w-full h-screen font-nunito">
|
||||
<Head :title="title" />
|
||||
|
||||
183
resources/js/Pages/Superuser/Permission/Index.vue
Normal file
183
resources/js/Pages/Superuser/Permission/Index.vue
Normal file
@@ -0,0 +1,183 @@
|
||||
<script setup>
|
||||
import { getCurrentInstance, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useForm } from '@inertiajs/inertia-vue3'
|
||||
import axios from 'axios'
|
||||
import Swal from 'sweetalert2'
|
||||
import DashboardLayout from '@/Layouts/DashboardLayout.vue'
|
||||
import Card from '@/Components/Card.vue'
|
||||
import Icon from '@/Components/Icon.vue'
|
||||
import { Inertia } from '@inertiajs/inertia'
|
||||
|
||||
const self = getCurrentInstance()
|
||||
const permissions = ref([])
|
||||
const search = ref('')
|
||||
const open = ref(false)
|
||||
const form = useForm({
|
||||
id: null,
|
||||
name: '',
|
||||
})
|
||||
|
||||
const fetch = async () => {
|
||||
try {
|
||||
const response = await axios.get(route('api.v1.superuser.permission'))
|
||||
permissions.value = response.data
|
||||
} catch (e) {
|
||||
Swal.fire({
|
||||
title: 'error',
|
||||
text: `${e}`,
|
||||
icon: 'error',
|
||||
})
|
||||
|
||||
setTimeout(fetch, 2500)
|
||||
}
|
||||
}
|
||||
|
||||
fetch()
|
||||
|
||||
const show = () => {
|
||||
open.value = true
|
||||
|
||||
nextTick(() => self.refs.name?.focus())
|
||||
}
|
||||
|
||||
const close = () => {
|
||||
open.value = false
|
||||
form.reset()
|
||||
form.clearErrors()
|
||||
}
|
||||
|
||||
const esc = e => {
|
||||
if (e.key === 'Escape') close()
|
||||
}
|
||||
|
||||
const store = () => form.post(route('superuser.permission.store'), {
|
||||
onSuccess: () => close() || fetch(),
|
||||
onError: show,
|
||||
})
|
||||
|
||||
const edit = permission => {
|
||||
form.id = permission.id
|
||||
form.name = permission.name
|
||||
show()
|
||||
}
|
||||
|
||||
const update = () => form.patch(route('superuser.permission.update', form.id), {
|
||||
onSuccess: () => close() || fetch(),
|
||||
onError: show,
|
||||
})
|
||||
|
||||
const destroy = async permission => {
|
||||
const response = await Swal.fire({
|
||||
title: 'Are you sure?',
|
||||
text: 'You can\'t restore it after deleted',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
})
|
||||
|
||||
if (response.isConfirmed) {
|
||||
return Inertia.delete(route('superuser.permission.destroy', permission.id), {
|
||||
onSuccess: fetch,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const submit = () => form.id ? update() : store()
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener('keydown', esc)
|
||||
|
||||
document.querySelector('[type=search]')?.focus()
|
||||
})
|
||||
onUnmounted(() => window.removeEventListener('keydown', esc))
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.opacity-enter-active, .opacity-leave-active {
|
||||
transition: all 100ms ease-in-out;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.opacity-enter-from, .opacity-enter-to {
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<DashboardLayout title="Permission">
|
||||
<Card class="bg-gray-100 dark:bg-slate-700 shadow-md">
|
||||
<template #header>
|
||||
<div class="flex items-center space-x-2 bg-gray-800 p-2">
|
||||
<button @click.prevent="show()" class="bg-green-600 rounded-md px-3 py-1 text-sm text-white">
|
||||
<div class="flex items-center space-x-1">
|
||||
<Icon name="plus" />
|
||||
<p class="font-semibold uppercase">create</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #body>
|
||||
<div class="flex flex-col">
|
||||
<div class="flex items-center space-x-2 text-sm dark:text-gray-100 px-4 py-2">
|
||||
<input v-model="search" type="search" class="bg-transparent w-full max-w-sm rounded-md placeholder:capitalize" placeholder="search">
|
||||
</div>
|
||||
|
||||
<div class="flex-wrap px-4 pb-2 dark:bg-gray-700 dark:text-gray-100 rounded-b-md">
|
||||
<transition-group name="opacity">
|
||||
<div v-for="(permission, i) in permissions.filter(p => p.name?.toLowerCase().includes(search?.trim().toLowerCase()))" :key="i" class="inline-block dark:bg-gray-800 dark:hover:bg-gray-900 transition-all border dark:border-gray-800 rounded-md m-[2px] px-3 py-1">
|
||||
<div class="flex items-center space-x-2 text-sm">
|
||||
<p class="uppercase">{{ permission.name }}</p>
|
||||
|
||||
<div class="flex items-center space-x-1">
|
||||
<Icon @click.prevent="edit(permission)" name="pen" class="px-2 py-1 rounded cursor-pointer bg-blue-600 hover:bg-blue-700 transition-all" />
|
||||
<Icon @click.prevent="destroy(permission)" name="trash" class="px-2 py-1 rounded cursor-pointer bg-red-600 hover:bg-red-700 transition-all" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
</DashboardLayout>
|
||||
|
||||
<transition name="fade">
|
||||
<div v-if="open" class="fixed top-0 left-0 w-full h-screen flex items-center justify-center bg-black bg-opacity-40">
|
||||
<form @submit.prevent="submit" class="w-full max-w-xl shadow-xl">
|
||||
<Card class="dark:bg-gray-700 dark:text-gray-100 border dark:border-gray-700">
|
||||
<template #header>
|
||||
<div class="flex items-center space-x-2 justify-end dark:bg-gray-800 dark:text-gray-50 p-2">
|
||||
<Icon @click.prevent="close" name="times" class="border border-transparent dark:bg-gray-700 px-2 py-1 rounded-md cursor-pointer transition-all dark:hover:bg-gray-800 dark:hover:border-gray-600" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #body>
|
||||
<div class="flex flex-col space-y-4 p-4">
|
||||
<div class="flex flex-col space-y-2">
|
||||
<div class="flex items-center space-x-2">
|
||||
<label for="name" class="lowercase first-letter:capitalize flex-none w-1/4">name</label>
|
||||
<input ref="name" type="text" v-model="form.name" class="bg-transparent w-full rounded-md px-3 py-1 text-sm placeholder:capitalize" placeholder="name">
|
||||
</div>
|
||||
|
||||
<transition name="fade">
|
||||
<div v-if="form.errors.name" class="text-red-400 text-sm text-right">{{ form.errors.name }}</div>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex items-center space-x-2 justify-end dark:bg-gray-800 dark:text-gray-50 p-2">
|
||||
<button type="submit" class="bg-green-600 rounded-md px-3 py-1 text-sm transition-all hover:bg-green-700">
|
||||
<div class="flex items-center space-x-1">
|
||||
<Icon name="check" />
|
||||
<p class="uppercase font-semibold">submit</p>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
</form>
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
@@ -2,11 +2,13 @@ import './bootstrap';
|
||||
import '../css/app.css';
|
||||
|
||||
import { createApp, h } from 'vue';
|
||||
import { createInertiaApp } from '@inertiajs/inertia-vue3';
|
||||
import { createInertiaApp, usePage } from '@inertiajs/inertia-vue3';
|
||||
import { InertiaProgress } from '@inertiajs/progress';
|
||||
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
|
||||
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
|
||||
import Themes from './themes'
|
||||
import Swal from 'sweetalert2';
|
||||
import { Inertia } from '@inertiajs/inertia';
|
||||
|
||||
const appName = window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';
|
||||
|
||||
@@ -27,3 +29,54 @@ createInertiaApp({
|
||||
});
|
||||
|
||||
InertiaProgress.init({ color: '#4B5563' });
|
||||
|
||||
window.Swal = Swal
|
||||
const Toast = Swal.mixin({
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
showConfirmButton: false,
|
||||
showCloseButton: true,
|
||||
timerProgressBar: true,
|
||||
didOpen: (toast) => {
|
||||
toast.addEventListener('mouseenter', Swal.stopTimer)
|
||||
toast.addEventListener('mouseleave', Swal.resumeTimer)
|
||||
}
|
||||
})
|
||||
|
||||
window.Toast = Toast
|
||||
|
||||
Inertia.on('finish', () => {
|
||||
const { $flash } = usePage().props.value
|
||||
const { success, error, info, warning } = $flash
|
||||
|
||||
if (success) {
|
||||
Toast.fire({
|
||||
text: success,
|
||||
timer: 3000,
|
||||
icon: 'success',
|
||||
})
|
||||
}
|
||||
|
||||
if (error) {
|
||||
Toast.fire({
|
||||
text: error,
|
||||
icon: 'error',
|
||||
})
|
||||
}
|
||||
|
||||
if (info) {
|
||||
Toast.fire({
|
||||
text: info,
|
||||
timer: 3000,
|
||||
icon: 'info',
|
||||
})
|
||||
}
|
||||
|
||||
if (warning) {
|
||||
Toast.fire({
|
||||
text: warning,
|
||||
timer: 3000,
|
||||
icon: 'warning',
|
||||
})
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user