mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: Implement UserProfiles
This commit is contained in:
parent
1bbb0269a3
commit
3b5c4f9d92
14 changed files with 1729 additions and 19 deletions
|
|
@ -1400,7 +1400,7 @@ const PeopleSectionEditor: React.FC<{
|
|||
<Label>People</Label>
|
||||
<div className="space-y-4 mt-2">
|
||||
{section.people.map((person, index) => (
|
||||
<div key={index} className="grid grid-cols-[1fr_1fr_1fr_auto] gap-4 p-4 border rounded-lg">
|
||||
<div key={index} className="grid grid-cols-[1fr_1fr_1fr_1fr_auto] gap-4 p-4 border rounded-lg">
|
||||
<div className="space-y-2">
|
||||
<Label>Name</Label>
|
||||
<Input
|
||||
|
|
@ -1414,6 +1414,19 @@ const PeopleSectionEditor: React.FC<{
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>Username</Label>
|
||||
<Input
|
||||
value={person.username || ''}
|
||||
onChange={(e) => {
|
||||
const newPeople = [...section.people]
|
||||
newPeople[index] = { ...person, username: e.target.value }
|
||||
onChange({ ...section, people: newPeople })
|
||||
}}
|
||||
placeholder="@username"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>Image</Label>
|
||||
<div className="space-y-2">
|
||||
|
|
@ -1480,7 +1493,8 @@ const PeopleSectionEditor: React.FC<{
|
|||
user_uuid: '',
|
||||
name: '',
|
||||
description: '',
|
||||
image_url: ''
|
||||
image_url: '',
|
||||
username: ''
|
||||
}
|
||||
onChange({
|
||||
...section,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ export interface LandingUsers {
|
|||
name: string;
|
||||
description: string;
|
||||
image_url: string;
|
||||
username?: string;
|
||||
}
|
||||
|
||||
export interface LandingPeople {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import React from 'react'
|
||||
import UserProfileBuilder from './UserProfileBuilder'
|
||||
|
||||
function UserProfile() {
|
||||
return (
|
||||
<div>UserProfile</div>
|
||||
<div>
|
||||
<UserProfileBuilder />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -7,6 +7,7 @@ import useSWR from 'swr'
|
|||
import { getOrgCourses } from '@services/courses/courses'
|
||||
import { useLHSession } from '@components/Contexts/LHSessionContext'
|
||||
import CourseThumbnailLanding from '@components/Objects/Thumbnails/CourseThumbnailLanding'
|
||||
import UserAvatar from '@components/Objects/UserAvatar'
|
||||
|
||||
interface LandingCustomProps {
|
||||
landing: {
|
||||
|
|
@ -183,11 +184,21 @@ function LandingCustom({ landing, orgslug }: LandingCustomProps) {
|
|||
{section.people.map((person, index) => (
|
||||
<div key={index} className="w-[140px] flex flex-col items-center">
|
||||
<div className="w-24 h-24 mb-4">
|
||||
<img
|
||||
src={person.image_url}
|
||||
alt={person.name}
|
||||
className="w-full h-full rounded-full object-cover border-4 border-white nice-shadow"
|
||||
/>
|
||||
{person.username ? (
|
||||
<UserAvatar
|
||||
username={person.username}
|
||||
width={96}
|
||||
rounded="rounded-full"
|
||||
border="border-4"
|
||||
showProfilePopup
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src={person.image_url}
|
||||
alt={person.name}
|
||||
className="w-full h-full rounded-full object-cover border-4 border-white nice-shadow"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold text-center text-gray-900">{person.name}</h3>
|
||||
<p className="text-sm text-center text-gray-600 mt-1">{person.description}</p>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import React from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { getUriWithOrg } from '@services/config/config'
|
||||
import { useParams } from 'next/navigation'
|
||||
import { getUserAvatarMediaDirectory } from '@services/media/media'
|
||||
import { useLHSession } from '@components/Contexts/LHSessionContext'
|
||||
import UserProfilePopup from './UserProfilePopup'
|
||||
import { getUserByUsername } from '@services/users/users'
|
||||
|
||||
type UserAvatarProps = {
|
||||
width?: number
|
||||
|
|
@ -16,11 +17,28 @@ type UserAvatarProps = {
|
|||
backgroundColor?: 'bg-white' | 'bg-gray-100'
|
||||
showProfilePopup?: boolean
|
||||
userId?: string
|
||||
username?: string
|
||||
}
|
||||
|
||||
function UserAvatar(props: UserAvatarProps) {
|
||||
const session = useLHSession() as any
|
||||
const params = useParams() as any
|
||||
const [userData, setUserData] = useState<any>(null)
|
||||
|
||||
useEffect(() => {
|
||||
const fetchUserByUsername = async () => {
|
||||
if (props.username && session?.data?.tokens?.access_token) {
|
||||
try {
|
||||
const data = await getUserByUsername(props.username, session.data.tokens.access_token)
|
||||
setUserData(data)
|
||||
} catch (error) {
|
||||
console.error('Error fetching user by username:', error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetchUserByUsername()
|
||||
}, [props.username, session?.data?.tokens?.access_token])
|
||||
|
||||
const isExternalUrl = (url: string): boolean => {
|
||||
return url.startsWith('http://') || url.startsWith('https://')
|
||||
|
|
@ -57,6 +75,17 @@ function UserAvatar(props: UserAvatarProps) {
|
|||
return props.avatar_url
|
||||
}
|
||||
|
||||
// If we have user data from username fetch
|
||||
if (userData?.avatar_image) {
|
||||
const avatarUrl = userData.avatar_image
|
||||
// If it's an external URL (e.g., from Google, Facebook, etc.), use it directly
|
||||
if (isExternalUrl(avatarUrl)) {
|
||||
return avatarUrl
|
||||
}
|
||||
// Otherwise, get the local avatar URL
|
||||
return getUserAvatarMediaDirectory(userData.user_uuid, avatarUrl)
|
||||
}
|
||||
|
||||
// If user has an avatar in session
|
||||
if (session?.data?.user?.avatar_image) {
|
||||
const avatarUrl = session.data.user.avatar_image
|
||||
|
|
@ -92,9 +121,9 @@ function UserAvatar(props: UserAvatarProps) {
|
|||
/>
|
||||
)
|
||||
|
||||
if (props.showProfilePopup && props.userId) {
|
||||
if (props.showProfilePopup && (props.userId || (userData?.id))) {
|
||||
return (
|
||||
<UserProfilePopup userId={props.userId}>
|
||||
<UserProfilePopup userId={props.userId || userData?.id}>
|
||||
{avatarImage}
|
||||
</UserProfilePopup>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ const UserProfilePopup = ({ children, userId }: UserProfilePopupProps) => {
|
|||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-6 w-6 text-gray-600 hover:text-gray-900 flex-shrink-0"
|
||||
onClick={() => router.push(`/profile/${userId}`)}
|
||||
onClick={() => userData.username && router.push(`/user/${userData.username}`)}
|
||||
>
|
||||
<ExternalLink className="w-4 h-4" />
|
||||
</Button>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue