mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
fix: profile issues
This commit is contained in:
parent
b3ef0eb10b
commit
fe38020f02
5 changed files with 74 additions and 26 deletions
|
|
@ -14,7 +14,8 @@ import {
|
|||
Laptop2,
|
||||
Users,
|
||||
Calendar,
|
||||
Lightbulb
|
||||
Lightbulb,
|
||||
X
|
||||
} from 'lucide-react'
|
||||
import { getUserAvatarMediaDirectory } from '@services/media/media'
|
||||
|
||||
|
|
@ -38,7 +39,36 @@ const ICON_MAP = {
|
|||
'calendar': Calendar,
|
||||
} as const
|
||||
|
||||
// Add Modal component
|
||||
const ImageModal: React.FC<{
|
||||
image: { url: string; caption?: string };
|
||||
onClose: () => void;
|
||||
}> = ({ image, onClose }) => {
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/80 z-50 flex items-center justify-center p-4">
|
||||
<div className="relative max-w-4xl w-full">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="absolute -top-10 right-0 text-white hover:text-gray-300 transition-colors"
|
||||
>
|
||||
<X className="w-6 h-6" />
|
||||
</button>
|
||||
<img
|
||||
src={image.url}
|
||||
alt={image.caption || ''}
|
||||
className="w-full h-auto rounded-lg"
|
||||
/>
|
||||
{image.caption && (
|
||||
<p className="mt-4 text-white text-center text-lg">{image.caption}</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
function UserProfileClient({ userData, profile }: UserProfileClientProps) {
|
||||
const [selectedImage, setSelectedImage] = React.useState<{ url: string; caption?: string } | null>(null);
|
||||
|
||||
const IconComponent = ({ iconName }: { iconName: string }) => {
|
||||
const IconElement = ICON_MAP[iconName as keyof typeof ICON_MAP]
|
||||
if (!IconElement) return null
|
||||
|
|
@ -127,6 +157,30 @@ function UserProfileClient({ userData, profile }: UserProfileClientProps) {
|
|||
<div key={index} className="mb-8">
|
||||
<h2 className="text-xl font-semibold mb-4">{section.title}</h2>
|
||||
|
||||
{/* Add Image Gallery section */}
|
||||
{section.type === 'image-gallery' && (
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
{section.images.map((image: any, imageIndex: number) => (
|
||||
<div
|
||||
key={imageIndex}
|
||||
className="relative group cursor-pointer"
|
||||
onClick={() => setSelectedImage(image)}
|
||||
>
|
||||
<img
|
||||
src={image.url}
|
||||
alt={image.caption || ''}
|
||||
className="w-full h-48 object-cover rounded-lg"
|
||||
/>
|
||||
{image.caption && (
|
||||
<div className="absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity duration-200 rounded-lg flex items-center justify-center p-4">
|
||||
<p className="text-white text-center text-sm">{image.caption}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{section.type === 'text' && (
|
||||
<div className="prose max-w-none">{section.content}</div>
|
||||
)}
|
||||
|
|
@ -227,6 +281,14 @@ function UserProfileClient({ userData, profile }: UserProfileClientProps) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Image Modal */}
|
||||
{selectedImage && (
|
||||
<ImageModal
|
||||
image={selectedImage}
|
||||
onClose={() => setSelectedImage(null)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,17 +17,11 @@ interface UserPageProps {
|
|||
|
||||
export async function generateMetadata({ params }: UserPageProps): Promise<Metadata> {
|
||||
try {
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
const resolvedParams = await params
|
||||
|
||||
if (!access_token) {
|
||||
return {
|
||||
title: 'User Profile',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const userData = await getUserByUsername(resolvedParams.username, access_token)
|
||||
const userData = await getUserByUsername(resolvedParams.username)
|
||||
return {
|
||||
title: `${userData.first_name} ${userData.last_name} | Profile`,
|
||||
description: userData.bio || `Profile page of ${userData.first_name} ${userData.last_name}`,
|
||||
|
|
@ -44,16 +38,8 @@ async function UserPage({ params }: UserPageProps) {
|
|||
const { username } = resolvedParams;
|
||||
|
||||
try {
|
||||
// Get access token from server session
|
||||
const session = await getServerSession(nextAuthOptions)
|
||||
const access_token = session?.tokens?.access_token
|
||||
|
||||
if (!access_token) {
|
||||
throw new Error('No access token available')
|
||||
}
|
||||
|
||||
// Fetch user data by username
|
||||
const userData = await getUserByUsername(username, access_token);
|
||||
const userData = await getUserByUsername(username);
|
||||
const profile = userData.profile ? (
|
||||
typeof userData.profile === 'string' ? JSON.parse(userData.profile) : userData.profile
|
||||
) : { sections: [] };
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ const UserProfileBuilder = () => {
|
|||
if (session?.data?.user?.id && access_token) {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
const userData = await getUser(session.data.user.id, access_token)
|
||||
const userData = await getUser(session.data.user.id)
|
||||
|
||||
if (userData.profile) {
|
||||
try {
|
||||
|
|
@ -291,7 +291,7 @@ const UserProfileBuilder = () => {
|
|||
|
||||
try {
|
||||
// Get fresh user data before update
|
||||
const userData = await getUser(session.data.user.id, access_token)
|
||||
const userData = await getUser(session.data.user.id)
|
||||
|
||||
// Update only the profile field
|
||||
userData.profile = profileData
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ function UserAvatar(props: UserAvatarProps) {
|
|||
|
||||
useEffect(() => {
|
||||
const fetchUserByUsername = async () => {
|
||||
if (props.username && session?.data?.tokens?.access_token) {
|
||||
if (props.username) {
|
||||
try {
|
||||
const data = await getUserByUsername(props.username, session.data.tokens.access_token)
|
||||
const data = await getUserByUsername(props.username)
|
||||
setUserData(data)
|
||||
} catch (error) {
|
||||
console.error('Error fetching user by username:', error)
|
||||
|
|
@ -38,7 +38,7 @@ function UserAvatar(props: UserAvatarProps) {
|
|||
}
|
||||
|
||||
fetchUserByUsername()
|
||||
}, [props.username, session?.data?.tokens?.access_token])
|
||||
}, [props.username])
|
||||
|
||||
const isExternalUrl = (url: string): boolean => {
|
||||
return url.startsWith('http://') || url.startsWith('https://')
|
||||
|
|
@ -86,7 +86,7 @@ function UserAvatar(props: UserAvatarProps) {
|
|||
return getUserAvatarMediaDirectory(userData.user_uuid, avatarUrl)
|
||||
}
|
||||
|
||||
// If user has an avatar in session
|
||||
// If user has an avatar in session (only if session exists)
|
||||
if (session?.data?.user?.avatar_image) {
|
||||
const avatarUrl = session.data.user.avatar_image
|
||||
// If it's an external URL (e.g., from Google, Facebook, etc.), use it directly
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
getResponseMetadata,
|
||||
} from '@services/utils/ts/requests'
|
||||
|
||||
export async function getUser(user_id: string, access_token: string) {
|
||||
export async function getUser(user_id: string) {
|
||||
const result = await fetch(
|
||||
`${getAPIUrl()}users/id/${user_id}`,
|
||||
RequestBody('GET', null, null)
|
||||
|
|
@ -16,7 +16,7 @@ export async function getUser(user_id: string, access_token: string) {
|
|||
return res
|
||||
}
|
||||
|
||||
export async function getUserByUsername(username: string, access_token: string) {
|
||||
export async function getUserByUsername(username: string) {
|
||||
const result = await fetch(
|
||||
`${getAPIUrl()}users/username/${username}`,
|
||||
RequestBody('GET', null, null)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue