Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions src/app/friendList/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,11 @@ const FriendListPage = () => {
const handleFriendPlus = () => {
setIsModalOpen(true)
}
const friendData = [
{ id: 1, name: '신혜민', tag: 1111, profile: user.user?.profileImage },
{ id: 2, name: '김의진', tag: 1112, profile: user.user?.profileImage },
{ id: 3, name: '강보석', tag: 1113, profile: user.user?.profileImage },
{ id: 4, name: '송수빈', tag: 1114, profile: user.user?.profileImage },
{ id: 5, name: '유성현', tag: 1115, profile: user.user?.profileImage },
{ id: 6, name: '짱똘', tag: 1116, profile: user.user?.profileImage },
]

const fetchFriendList = async () => {
console.log(user.user?.id)
if (user) {
const friendList = await getFriendList(user.user?.id || null)
const friendList = await getFriendList(user.user?.id || null,null)
console.log('제발용',friendList)
setFriendsData(friendList)
}
Expand Down
119 changes: 81 additions & 38 deletions src/app/notification/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ import DetailHeader from '@/components/common/header/DetailHeader'
import { getNotification } from '@/lib/notification'
import useUserStore from '@/stores/useAuthStore'
import { Notification } from '@/types/notification'
import Icon from '@/components/common/icon/Icon'
import Spinner from '@/components/common/spinner/Spinner'
import { useToast } from '@/components/common/toast/Toast'
import { useRouter } from 'next/navigation'
import { Json } from '@/types/supabase'
import { getRelativeTime } from '@/utils/getRelativeTime'

import FriendAcceptModal from '@/components/friend/FriendAcceptModal'
import InviteAcceptModal from '@/components/invite/InviteAcceptModal'
const Page = () => {
const [notificationData, setNotificationData] = useState<Notification[]>([])
const [selectedNotifycationId, setSelectedNotifycationId] = useState<
Expand All @@ -25,45 +22,37 @@ const Page = () => {
useState<string | null>(null)
const [isLoading, setIsLoading] = useState<boolean>(true)
const userData = useUserStore((state) => state.user)
const router = useRouter()

const [isAcceptModalOpen, setIsAcceptModalOpen] = useState(false)
const [isInviteAcceptModalOpen, setIsInviteAcceptModalOpen] = useState(false)
const fetchNotifications = async () => {
setIsLoading(true)
const data = await getNotification(userData!.id)
const sortedDataByCreatedAt = data.sort(
(a, b) => Number(new Date(b.created_at)) - Number(new Date(a.created_at)),
)
setNotificationData(sortedDataByCreatedAt)
console.log(sortedDataByCreatedAt)
setIsLoading(false)
}

// -------------- 알림 아이템 클릭 시 알림 타입에 따라 처리하는 함수 ------------- //
function notificationOnclickHandler(type: string, data: Json | null) {
const parsedData = data as Record<string, unknown>
function getRelativeTime(utcDateString: string): string {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/utils/getRelativeTime 함수를 재사용하면 좋을 것 같습니다!

const KST_OFFSET = 9 * 60 * 60 * 1000 // 한국은 UTC+9
const now = new Date(Date.now() + KST_OFFSET)
const past = new Date(new Date(utcDateString).getTime() + KST_OFFSET)

console.log(type, data)
if (!type || !data) {
useToast.error('잘못된 요청입니다. 다시 시도해주세요.')
return
}
const diff = now.getTime() - past.getTime()

switch (type) {
// chat, payment : 해당 엔빵 페이지로 이동
case 'chat':
case 'payment':
const nbreadId = parsedData['nbreadId'] as string
router.replace(`/nbread/${nbreadId}`)
break
case 'nbread-invite':
// NOTE 엔빵 초대 관련 로직 추가
break
const minutes = Math.floor(diff / (1000 * 60))
const hours = Math.floor(diff / (1000 * 60 * 60))
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
const month = Math.floor(diff / (1000 * 60 * 60 * 24 * 30))
const year = Math.floor(diff / (1000 * 60 * 60 * 24 * 30 * 12))

case 'friend-request':
// NOTE 친구 초대 관련 로직 추가
break
}
if (minutes < 1) return '방금 전'
if (minutes < 60) return `${minutes}분 전`
if (hours < 24) return `${hours}시간 전`
if (days < 30) return `${days}일 전`
if (month < 12) return `${month}개월 전`
return `${year}년 전`
}

useEffect(() => {
Expand All @@ -74,37 +63,80 @@ const Page = () => {
useEffect(() => {
if (selectedNotifycationType === 'friend_request') {
setIsAcceptModalOpen(true)
} else if (selectedNotifycationType === 'invite') {
setIsInviteAcceptModalOpen(true)
}
}, [selectedNotifycationType])
if (isLoading) {
return <Spinner isLoading={isLoading} />
}

return (
<div className="jusfity-between flex h-full w-full flex-col overflow-y-hidden">
<div className="jusfity-between flex h-screen w-full flex-col overflow-y-hidden">
<div className="pl-24 pt-24">
<DetailHeader />
</div>
<div className="mb-16 flex flex-row items-end justify-between px-24 pt-24">
<header className="text-heading02 text-gray-800">알림</header>
<div
className="cursor-pointer pb-2 text-body02 text-gray-400"
onClick={
() => null // TODO 알림 모두 지우기 함수 추가
}
>
모두 지우기
</div>
</div>

<div className="flex flex-col justify-between gap-8 overflow-y-auto px-20 pb-40 pt-4">
{notificationData.map((item, _) => (
<div className="flex flex-col justify-between gap-8 px-20">
{notificationData.map((data, index) => (
<div
className="card card-clickable relative flex cursor-pointer flex-row justify-between"
key={item.id}
onClick={() => notificationOnclickHandler(item.type, item.data)}
key={data.id}
onClick={() => {
setSelectedNotifycationId(data.id)
setSelectedNotifycationType(data.type)
if (data.type === 'invite') {
// 엔빵 초대 알림일 경우
setSelectedNotifycationSenderName(
(data.data as any)?.nbreadTitle ?? null,
)
setSelectedNotifycationSenderId(
(data.data as any)?.nbreadId ?? null,
)
} else if (data.type === 'friend_request') {
// 친구 요청 알림일 경우
setSelectedNotifycationSenderName(
(data.data as any)?.sender_name ?? null,
)
setSelectedNotifycationSenderId(
(data.data as any)?.sender_id ?? null,
)
}
}}
>
<div className="flex w-full flex-col gap-4">
<div className="text-body01 text-gray-800">{item.title}</div>
<div className="text-body01 text-gray-800">{data.title}</div>
<div className="flex w-full flex-row justify-between">
<div className="text-body02 text-gray-600">{item.message}</div>
<div className="text-body02 text-gray-600">{data.message}</div>
<div className="text-body02 text-gray-300">
{getRelativeTime(item.created_at)}
{getRelativeTime(data.created_at)}
</div>
</div>
</div>
<div
className="absolute right-12 top-12 cursor-pointer"
onClick={
() => null // TODO 알림 삭제 함수 추가
}
>
<Icon
type={'cross'}
width={16}
height={16}
fill={'text-gray-400'}
/>
</div>
</div>
))}
</div>
Expand All @@ -119,6 +151,17 @@ const Page = () => {
senderUserName={selectedNotifycationSenderName}
receiverId={userData?.id as string}
/>
<InviteAcceptModal
id={selectedNotifycationId}
isOpen={isInviteAcceptModalOpen}
onClose={() => {
setIsInviteAcceptModalOpen(false)
setSelectedNotifycationType(null)
}}
senderNbreadId={selectedNotifycationSenderId}
senderNbreadTitle={selectedNotifycationSenderName}
receiverId={userData?.id as string}
/>
</div>
)
}
Expand Down
1 change: 1 addition & 0 deletions src/components/friend/FriendCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const FriendCard = ({ profile, name, tag }: friendProps) => {
<DefaultAvatar className="h-32 w-32rounded-full object-cover" />
)}
<p className="text-body-02">{name}</p>
<p className="text-body-02 text-secondary-100">#{tag}</p>
</div>
<Icon type="angleRight" width={16} height={16} onClick={handleBottomSheetOpen}/>
<FriendBottomSheet isOpen={isBottomSheet} onClose={handleBottomSheetOpen}
Expand Down
51 changes: 51 additions & 0 deletions src/components/invite/InviteAcceptModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Modal from '../common/modal/Modal'
import { useRouter } from 'next/navigation'
import { updateAcceptInvite } from '@/lib/invite/updateInvite'
import { updateRejectedInvite } from '@/lib/invite/updateInvite'
interface InviteAcceptModalProps {
id: number | null
isOpen: boolean
onClose: () => void
senderNbreadTitle: string | null
senderNbreadId: string | null
receiverId: string
}
const InviteAcceptModal = ({isOpen,onClose,senderNbreadTitle,senderNbreadId,receiverId} : InviteAcceptModalProps) => {
const router = useRouter()
const fetchInviteAccept = async () => {
const acceptInviteData = await updateAcceptInvite(receiverId,senderNbreadId)
onClose()
router.push(`/nbread/${senderNbreadId}`)

}
const fetchInviteReject = async () => {
const rejectInviteData = await updateRejectedInvite(receiverId,senderNbreadId)
onClose()
}
return (
<Modal isOpen={isOpen} onClose={onClose}>
<div className="flex flex-col gap-32 px-12 pb-8">
<div className="flex flex-col gap-8">
<h5>엔빵 초대를 수락하시겠어요?</h5>
<p className="text-body02">
{senderNbreadTitle}의 초대를 수락하시겠어요?
</p>
</div>
<div className="flex h-48 flex-row gap-8">
<button className="btn w-112 bg-gray-200 text-heading05"
onClick={fetchInviteReject}
>
거절하기
</button>
<button
className="btn w-112 bg-secondary-100 text-heading05"
onClick={fetchInviteAccept}
>
수락하기
</button>
</div>
</div>
</Modal>
)
}
export default InviteAcceptModal
Loading