Skip to content
This repository was archived by the owner on Dec 3, 2025. It is now read-only.
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/Actions/Fortify/CreateNewUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace App\Actions\Fortify;

use App\Enums\Role;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
Expand All @@ -28,6 +29,7 @@ public function create(array $input): User
"name" => $input["name"],
"email" => $input["email"],
"password" => Hash::make($input["password"]),
"role" => Role::User->value,
]);
}
}
2 changes: 1 addition & 1 deletion app/Enums/Role.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ enum Role: string
{
case Admin = "admin";
case User = "user";
case ShelterEmployee = "shelter employee";
case ShelterEmployee = "shelterEmployee";
}
2 changes: 1 addition & 1 deletion app/Http/Middleware/HandleInertiaRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function share(Request $request): array
return [
...parent::share($request),
"auth" => [
"user" => $request->user() ? new UserResource($request->user()) : null,
"user" => $request->user() ? (new UserResource($request->user()))->resolve() : null,
],
];
}
Expand Down
32 changes: 19 additions & 13 deletions resources/js/Components/FormSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,29 @@ const hasActions = computed(() => !! useSlots().actions)
</script>

<template>
<div class="md:grid md:grid-cols-3 md:gap-6">
<SectionTitle>
<template #title>
<slot name="title" />
</template>
<template #description>
<slot name="description" />
</template>
</SectionTitle>
<div class="flex flex-row min-h-[300px] justify-center">
<div class="flex flex-row justify-around items-center w-1/4 px-8">
<SectionTitle>
<template #title>
<div class="text-end text-xl">
<slot name="title" />
</div>
</template>
<template #description>
<div class="mt-2 text-end">
<slot name="description" />
</div>
</template>
</SectionTitle>
</div>

<div class="mt-5 md:mt-0 md:col-span-2">
<form @submit.prevent="$emit('submitted')">
<div class="flex flex-row justify-center items-center w-1/2 px-8">
<form class="w-full max-w-md" @submit.prevent="$emit('submitted')">
<div
class="px-4 py-5 sm:p-6 rounded"
class="px-4 py-5 sm:p-6 rounded bg-white shadow "
:class="hasActions ? 'sm:rounded-tl-md sm:rounded-tr-md' : 'sm:rounded-md'"
>
<div class="grid mb-4 justify-center gap-6">
<div class="mb-4 gap-6 flex flex-col ">
<slot name="form" />
</div>
<div v-if="hasActions" class="flex items-center justify-end px-4 py-3 text-end sm:px-6 rounded sm:rounded-b-md">
Expand Down
1 change: 0 additions & 1 deletion resources/js/Components/Header.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ const mobileMenuOpen = ref(false)

<span v-else class="inline-flex rounded-md">
<button type="button" aria-label="User menu" class="inline-flex items-center px-3 py-2 text-sm font-semibold rounded-md text-gray-900 hover:bg-white transition ease-in-out duration-150">
{{ $page.props.auth.user.name }}
<IconMenu2 class="size-6" />
</button>
</span>
Expand Down
2 changes: 1 addition & 1 deletion resources/js/Components/TextInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ defineExpose({ focus: () => input.value.focus() })
<template>
<input
ref="input"
class="border-amber-200 border-3 rounded-xl bg-white text-gray-900 transition-all duration-300 ease-out focus:bg-orange-50/25 focus:border-orange-300 focus:ring-orange-300 placeholder:text-gray-400"
class="border-light-brown border-3 rounded-xl bg-white text-gray-900 transition-all duration-300 ease-out focus:bg-orange-50/25 focus:border-orange-300 focus:ring-orange-300 placeholder:text-gray-400"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
>
Expand Down
28 changes: 28 additions & 0 deletions resources/js/Pages/Profile/Components/EditProfile.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<script setup>
import UpdateProfileInformationForm from '@/Pages/Profile/Partials/UpdateProfileInformationForm.vue'
import UpdatePasswordForm from '@/Pages/Profile/Partials/UpdatePasswordForm.vue'

const props = defineProps({
user: {
type: Object,
default: () => ({}),
},
sessions: {
type: Array,
default: () => [],
},
})

</script>

<template>
<div class="flex flex-col min-w-full space-y-8">
<div v-if="$page.props.jetstream.canUpdateProfileInformation">
<UpdateProfileInformationForm :user="user" />
</div>

<div v-if="$page.props.jetstream.canUpdatePassword">
<UpdatePasswordForm />
</div>
</div>
</template>
26 changes: 26 additions & 0 deletions resources/js/Pages/Profile/Components/SecurityProfile.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup>
import LogoutOtherBrowserSessionsForm from '@/Pages/Profile/Partials/LogoutOtherBrowserSessionsForm.vue'
import DeleteUserForm from '@/Pages/Profile/Partials/DeleteUserForm.vue'
import { usePage } from '@inertiajs/vue3'
const props = defineProps({
sessions: {
type: Array,
default: () => [],
},
})

const page = usePage()

</script>

<template>
<div class="flex flex-col">
<div>
<LogoutOtherBrowserSessionsForm :sessions="sessions" />
</div>

<template v-if="$page.props.jetstream.hasAccountDeletionFeatures">
<DeleteUserForm />
</template>
</div>
</template>
212 changes: 212 additions & 0 deletions resources/js/Pages/Profile/Partials/ProfileSidebar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
<script setup>
import { ref, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import { Dialog, DialogPanel, TransitionChild, TransitionRoot } from '@headlessui/vue'
import {
Bars3Icon,
HomeIcon,
HeartIcon,
UserIcon,
XMarkIcon,
ArrowLeftIcon,
PencilIcon,
ShieldCheckIcon,
} from '@heroicons/vue/24/outline'
import { logo } from '@/helpers/mappers/logo'
import { router } from '@inertiajs/vue3'
import { routes } from '@/routes'
import { IconShield } from '@tabler/icons-vue'
const { t } = useI18n()

const props = defineProps({
user: {
type: Object,
required: true,
},
})

const emit = defineEmits(['view-change'])

const logout = () => {
router.post(routes.logout())
}

const viewChange = (view) => {
emit('view-change', view)
}

const selectNavigation = (clickedItem) => {
// ustawienie current dla wszystkich elementów
navigation.value.forEach(item => {
item.current = item === clickedItem
})

// wywołanie akcji
if (clickedItem.action) {
clickedItem.action()
}
}

const navigation = ref([
{
name: t('profile.editProfile'),
href: '#',
icon: PencilIcon,
current: true,
anchorClass: 'group cursor-pointer flex w-full gap-x-3 rounded-md p-2 text-left text-sm/6 font-semibold text-amber-800 hover:bg-amber-100 hover:text-amber-800',
iconClass: 'size-6 shrink-0 text-amber-800 group-hover:text-amber-800',
action: () => viewChange('editProfile'),
},
{
name: t('profile.security'),
href: '#',
icon: IconShield,
current: false,
anchorClass: 'group cursor-pointer flex w-full gap-x-3 rounded-md p-2 text-left text-sm/6 font-semibold text-amber-800 hover:bg-amber-100 hover:text-amber-800',
iconClass: 'size-6 shrink-0 text-amber-800 group-hover:text-amber-800',
action: () => viewChange('security'),
},
{
name: t('profile.favoritePets'),
href: '#',
icon: HeartIcon,
current: false,
anchorClass: 'group cursor-pointer flex w-full gap-x-3 rounded-md p-2 text-left text-sm/6 font-semibold text-amber-800 hover:bg-amber-100 hover:text-amber-800',
iconClass: 'size-6 shrink-0 text-amber-800 group-hover:text-amber-800',
action: () => viewChange('favoritePets'),
},
])

onMounted(() => {
if (props.user.role === 'shelterEmployee') {
navigation.value.push({
name: t('profile.myShelter'),
href: '#',
icon: HomeIcon,
current: false,
anchorClass: 'group cursor-pointer flex w-full gap-x-3 rounded-md p-2 text-left text-sm/6 font-semibold text-amber-800 hover:bg-amber-100 hover:text-amber-800',
iconClass: 'size-6 shrink-0 text-amber-800 group-hover:text-amber-800',
action: () => viewChange('myShelter'),
})
}
})

const sidebarOpen = ref(false)

</script>

<template>
<div class="-px-10 max-w-55 bg-amber-100/30 border-r-3 border-t-3 border-amber-100">
<TransitionRoot as="template" :show="sidebarOpen">
<Dialog class="relative z-50 lg:hidden" @close="sidebarOpen = false">
<TransitionChild as="template" enter="transition-opacity ease-linear duration-300" enter-from="opacity-0" enter-to="" leave="transition-opacity ease-linear duration-300" leave-from="" leave-to="opacity-0">
<div class="fixed inset-0 bg-gray-900/80" />
</TransitionChild>

<div class="fixed inset-0 flex">
<TransitionChild as="template" enter="transition ease-in-out duration-300 transform" enter-from="-translate-x-full" enter-to="translate-x-0" leave="transition ease-in-out duration-300 transform" leave-from="translate-x-0" leave-to="-translate-x-full">
<DialogPanel class="relative mr-16 flex w-full max-w-xs flex-1">
<TransitionChild as="template" enter="ease-in-out duration-300" enter-from="opacity-0" enter-to="" leave="ease-in-out duration-300" leave-from="" leave-to="opacity-0">
<div class="absolute top-0 left-full flex w-16 justify-center pt-5">
<button type="button" class="-m-2.5 p-2.5" @click="sidebarOpen = false">
<span class="sr-only">Close sidebar</span>
<XMarkIcon class="size-6 text-white" aria-hidden="true" />
</button>
</div>
</TransitionChild>

<div class="relative flex grow flex-col gap-y-5 overflow-y-auto px-6 pb-2">
<div class="relative flex h-16 shrink-0 items-center">
<img class="w-auto" :src="logo.Logo" alt="Your Company">
</div>
<nav class="relative flex flex-1 flex-col">
<ul role="list" class="flex flex-1 flex-col gap-y-7">
<li>
<ul role="list" class="-mx-2 space-y-1">
<li v-for="item in navigation" :key="item.name">
<component
:is="item.action ? 'button' : 'a'"
:href="!item.action ? item.href : undefined"
type="button"
:class="[item.anchorClass, item.current ? 'bg-amber-100' : 'bg-none']"
@click="selectNavigation(item)"
>
<component :is="item.icon" :class="item.iconClass" aria-hidden="true" />
{{ item.name }}
</component>
</li>
</ul>
</li>
</ul>
</nav>
</div>
</DialogPanel>
</TransitionChild>
</div>
</Dialog>
</TransitionRoot>
<div class="flex flex-col gap-y-5">
<nav class="flex flex-col gap-6 p-5 h-[calc(100vh-100px)]">
<ul role="list" class="flex flex-col gap-y-7">
<li>
<img class="bg-black w-40 rounded-md" src="https://lipsum.app/random/300x300" alt="Your profile">
</li>
<li>
<h4 class="heading-xl mb-0">{{ user.name }}</h4>
<p class="text-sm text-gray-500 mb-4"> {{ user.email }}</p>
<p class="text-sm text-gray-500 flex flex-row items-center gap-x-2">
<UserIcon class="size-6 shrink-0 text-black " aria-hidden="true" />
{{ t('enum.role.' + user.role) }}
</p>
</li>
</ul>
<ul role="list" class="flex flex-col justify-between h-full ">
<li>
<ul role="list" class="-mx-2 space-y-1">
<li v-for="item in navigation" :key="item.name">
<component
:is="item.action ? 'button' : 'a'"
:href="!item.action ? item.href : undefined"
type="button"
:class="[item.anchorClass, item.current ? 'bg-amber-100' : 'bg-none']"
@click="selectNavigation(item)"
>
<component :is="item.icon" :class="item.iconClass" aria-hidden="true" />
{{ item.name }}
</component>
</li>
</ul>
</li>
<li>
<ul role="list" class="-mx-2 space-y-1">
<li>
<button type="button" class="group cursor-pointer flex w-full gap-x-3 rounded-md p-2 text-left text-sm/6 font-semibold text-red-600 hover:text-red-700 hover:bg-red-100" @click="logout">
<ArrowLeftIcon class="size-6 shrink-0 text-red-500 group-hover:text-red-600" aria-hidden="true" />
{{ t('navigation.logOut') }}
</button>
</li>
</ul>
</li>
</ul>
</nav>
</div>

<div class="sticky top-0 z-40 flex items-center gap-x-6 bg-white p-4 shadow-xs sm:px-6 lg:hidden">
<button type="button" class="-m-2.5 p-2.5 text-gray-700 hover:text-gray-900 lg:hidden" @click="sidebarOpen = true">
<span class="sr-only">Open sidebar</span>
<Bars3Icon class="size-6" aria-hidden="true" />
</button>
<div class="flex-1 text-sm/6 font-semibold text-gray-900">Dashboard</div>
<a href="#">
<span class="sr-only">Your profile</span>
<img class="size-8 rounded-full bg-gray-50 outline -outline-offset-1 outline-black/5" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="">
</a>
</div>

<main class="lg:pl-72">
<div class="px-4 sm:px-6 lg:px-8">
<!-- Your content -->
</div>
</main>
</div>
</template>
Loading