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}
+
)
}