diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2d0ae73..58e5f61 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,5 +1,6 @@ class ApplicationController < ActionController::Base include Pagy::Method + include UserProfileable # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has. allow_browser versions: :modern diff --git a/app/controllers/concerns/user_profileable.rb b/app/controllers/concerns/user_profileable.rb new file mode 100644 index 0000000..f6a6bbb --- /dev/null +++ b/app/controllers/concerns/user_profileable.rb @@ -0,0 +1,22 @@ +module UserProfileable + extend ActiveSupport::Concern + + included do + inertia_share do + { + user_profile_id: params[:user_profile_id]&.to_i, + user_profile: load_user_profile + }.compact + end + end + + private + + def load_user_profile + return nil if params[:user_profile_id].blank? + sleep 1 + + User.find_by(id: params[:user_profile_id]) + &.as_json(only: [ :username, :email, :about_me, :id, :topics_count, :messages_count ]) + end +end diff --git a/app/frontend/components/Avatar.tsx b/app/frontend/components/Avatar.tsx index 4ab763d..24d781e 100644 --- a/app/frontend/components/Avatar.tsx +++ b/app/frontend/components/Avatar.tsx @@ -1,20 +1,35 @@ +import { Link, router } from '@inertiajs/react' import { User } from '../types' const Avatar = ({ user }: { user: User }) => { - const { username } = user; + const { username, id } = user; if (!user) { return null; } + const handleClick = (url: string) => { + router.push({ + url, + props: (currentProps) => ({ ...currentProps, user_profile_id: id }), + preserveState: true, + preserveScroll: true, + }) + } + return ( -
handleClick(e.url.toString())} > {username.charAt(0).toUpperCase()} -
+ ) } -export default Avatar \ No newline at end of file +export default Avatar diff --git a/app/frontend/components/UserProfileModal.tsx b/app/frontend/components/UserProfileModal.tsx new file mode 100644 index 0000000..31b6523 --- /dev/null +++ b/app/frontend/components/UserProfileModal.tsx @@ -0,0 +1,47 @@ +import Modal from './Modal' +import {router, usePage} from '@inertiajs/react' + +import LoadingSpinner from '@/components/LoadingSpinner'; +import UserProfile from '@/components/UserProfile'; +import type {User} from '@/types' + +export default function UserProfileModal() { + const {props: {user_profile_id: userProfileId, user_profile: userProfile}} = usePage<{ + user_profile_id: number, + user_profile: User + }>() + + const isLoading = userProfileId && !userProfile; + + const handleClose = () => { + const pathname = window.location.pathname; + const params = new URLSearchParams(window.location.search); + params.delete('user_profile_id'); + + const queryString = params.toString(); + const url = queryString ? `${pathname}?${queryString}` : pathname; + + router.visit(url, { + preserveScroll: true, + preserveState: true, + onBefore: (e) => { + router.push({ + url: e.url.toString(), + props: (currentProps) => ({...currentProps, user_profile_id: null}), + preserveState: true, + preserveScroll: true, + }) + } + }) + } + + return ( + + {isLoading ? ( + + ) : ( + + )} + + ) +} diff --git a/app/frontend/layouts/AppLayout.tsx b/app/frontend/layouts/AppLayout.tsx index b5c95a0..49cb42e 100644 --- a/app/frontend/layouts/AppLayout.tsx +++ b/app/frontend/layouts/AppLayout.tsx @@ -6,8 +6,10 @@ import { MagnifyingGlassIcon, ChevronDownIcon } from '@heroicons/react/24/outline' + import { User } from '@/types' import Sidebar from "@/components/Sidebar"; +import UserProfileModal from '../components/UserProfileModal' interface AppLayoutProps { children: ReactNode @@ -95,6 +97,7 @@ export default function AppLayout({ children }: AppLayoutProps) { {children} + ) }