Skip to content

Commit

Permalink
add avatar display and people pages
Browse files Browse the repository at this point in the history
  • Loading branch information
ngquyduc committed Jul 13, 2023
1 parent 28e672e commit a1e9ca8
Show file tree
Hide file tree
Showing 14 changed files with 328 additions and 60 deletions.
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
27 changes: 27 additions & 0 deletions app/actions/getCurrentUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import prisma from '@/app/libs/prismadb'

import getSession from './getSession'

const getCurrentUser = async () => {
try {
const session = await getSession()

if (!session?.user?.email) {
return null
}
const currentUser = await prisma.user.findUnique({
where: {
email: session.user.email as string,
},
})

if (!currentUser) {
return null
}
return currentUser
} catch (error: any) {
return null
}
}

export default getCurrentUser
6 changes: 6 additions & 0 deletions app/actions/getSession.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { getServerSession } from 'next-auth'
import { authOptions } from '../api/auth/[...nextauth]/route'

export default async function getSession() {
return await getServerSession(authOptions)
}
30 changes: 30 additions & 0 deletions app/actions/getUsers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import prisma from '@/app/libs/prismadb'

import getSession from './getSession'

const getUsers = async () => {
const session = await getSession()

if (!session?.user?.email) {
return []
}

try {
const users = await prisma.user.findMany({
orderBy: {
createdAt: 'desc',
},
where: {
NOT: {
email: session.user.email,
},
},
})

return users
} catch (error: any) {
return []
}
}

export default getUsers
25 changes: 25 additions & 0 deletions app/components/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client'

import { User } from '@prisma/client'
import Image from 'next/image'

interface AvatarProps {
user?: User
}

const Avatar: React.FC<AvatarProps> = ({ user }) => {
return (
<div className="relative">
<div className="relative inline-block rounded-full overflow-hidden h-9 w-9 md:h-11 md:w-11">
<Image
alt="Avatar"
src={user?.image || '/images/placeholder.jpeg'}
fill
/>
</div>
<span className="absolute block rounded-full bg-green-500 ring-2 ring-white top-0 right-0 h-2 w-2 md:h-3 md:w-3" />
</div>
)
}

export default Avatar
18 changes: 17 additions & 1 deletion app/components/sidebar/DesktopSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
'use client'

import useRoutes from '@/app/hooks/useRoutes'
import { User } from '@prisma/client'
import { useState } from 'react'
import Avatar from '../Avatar'
import DesktopItem from './DesktopItem'

const DesktopSidebar = () => {
interface DesktopSidebarProps {
currentUser: User
}

const DesktopSidebar: React.FC<DesktopSidebarProps> = ({ currentUser }) => {
const routes = useRoutes()
const [isOpen, setIsOpen] = useState(false)
console.log({ currentUser })

return (
<div className="hidden lg:fixed lg:inset-y-0 lg:left-0 lg:z-40 lg:w-20 xl:px-6 lg:overflow-y-auto lg:bg-white lg:border-r-[1px] lg:pb-4 lg:flex lg:flex-col justify-between">
<nav className="mt-4 flex-4 flex-col justify-between">
Expand All @@ -23,6 +31,14 @@ const DesktopSidebar = () => {
))}
</ul>
</nav>
<nav className="mt-4 flex flex-col justify-between items-center">
<div
onClick={() => setIsOpen(true)}
className="cursor-pointer hover:opacity-75 transition"
>
<Avatar user={currentUser} />
</div>
</nav>
</div>
)
}
Expand Down
4 changes: 3 additions & 1 deletion app/components/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import getCurrentUser from '@/app/actions/getCurrentUser'
import DesktopSidebar from './DesktopSidebar'
import MobileFooter from './MobileFooter'

async function Sidebar({ children }: { children: React.ReactNode }) {
const currentUser = await getCurrentUser()
return (
<div className="h-full">
<DesktopSidebar />
<DesktopSidebar currentUser={currentUser!} />
<MobileFooter />
<main className="lg:pl-20 h-full"> {children}</main>
</div>
Expand Down
44 changes: 44 additions & 0 deletions app/users/components/UserBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
'use client'

import Avatar from '@/app/components/Avatar'
import { User } from '@prisma/client'
import axios from 'axios'
import { useRouter } from 'next/navigation'
import { useCallback, useState } from 'react'

interface UserBoxProps {
data: User
}

const UserBox: React.FC<UserBoxProps> = ({ data }) => {
const router = useRouter()
const [isLoading, setIsLoading] = useState(false)

const handleClick = useCallback(() => {
setIsLoading(true)

axios
.post('/api/conversations', {
userId: data.id,
})
.then((data) => router.push(`/conversations/${data.data.id}`))
.finally(() => setIsLoading(false))
}, [data, router])
return (
<div
onClick={handleClick}
className="w-full relative flex items-center space-x-3 bg-white p-3 hover:bg-neutral-100 rounded-lg transition cursor-pointer"
>
<Avatar user={data} />
<div className="min-w-0 flex-1">
<div className="focus:outline-none">
<div className="flex justify-between items-center mb-1">
<p className="font-medium text-gray-900">{data.name}</p>
</div>
</div>
</div>
</div>
)
}

export default UserBox
25 changes: 25 additions & 0 deletions app/users/components/UserList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client'

import { User } from '@prisma/client'
import UserBox from './UserBox'

interface UserListProps {
items: User[]
}

const UserList: React.FC<UserListProps> = ({ items }) => {
return (
<aside className="fixed inset-y-0 pb-20 lg:pb-0 lg:left-20 lg:w-80 lg:block overflow-y-auto border-r border-gray-200 block w-full left-0">
<div className="px-5">
<div className="flex-col">
<div className="text-2xl font-bold text-neutral-800 py-4">People</div>
</div>
{items.map((item) => (
<UserBox key={item.id} data={item} />
))}
</div>
</aside>
)
}

export default UserList
8 changes: 7 additions & 1 deletion app/users/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import getUsers from '../actions/getUsers'
import Sidebar from '../components/sidebar/Sidebar'
import UserList from './components/UserList'

export default async function UserLayout({
children,
}: {
children: React.ReactNode
}) {
const users = await getUsers()
return (
// @ts-expect-error Server Component
<Sidebar>
<div className="h-full">{children}</div>
<div className="h-full">
<UserList items={users} />
{children}
</div>
</Sidebar>
)
}
10 changes: 9 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
/** @type {import('next').NextConfig} */
const nextConfig = {}
const nextConfig = {
experimental: {
appDir: true,
swcPlugins: [['next-superjson-plugin', {}]],
},
images: {
domains: ['res.cloudinary.com', 'lh3.googleusercontent.com'],
},
}

module.exports = nextConfig
Loading

0 comments on commit a1e9ca8

Please sign in to comment.