Skip to content
Merged
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
4 changes: 0 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>독크독크</title>
<script
type="text/javascript"
src="//dapi.kakao.com/v2/maps/sdk.js?appkey=%VITE_KAKAO_MAP_KEY%&libraries=services"
></script>
</head>
<body>
<div id="root"></div>
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@radix-ui/react-tabs": "^1.1.13",
"@radix-ui/react-toggle": "^1.1.10",
"@radix-ui/react-toggle-group": "^1.1.11",
"@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/vite": "^4.1.18",
"@tanstack/react-query": "^5.90.16",
"axios": "^1.13.2",
Expand Down
39 changes: 39 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { RouterProvider } from 'react-router-dom'
import { setupInterceptors } from '@/api'
import { queryClient } from '@/shared/lib/tanstack-query'
import { GlobalModalHost } from '@/shared/ui/GlobalModalHost'
import { TooltipProvider } from '@/shared/ui/Tooltip'

import { router } from './routes'

Expand All @@ -13,8 +14,10 @@ setupInterceptors()
function App() {
return (
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
<GlobalModalHost />
<TooltipProvider>
<RouterProvider router={router} />
<GlobalModalHost />
</TooltipProvider>
</QueryClientProvider>
)
}
Expand Down
11 changes: 7 additions & 4 deletions src/features/meetings/components/MeetingApprovalItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import { useGlobalModalStore } from '@/store'
export type MeetingApprovalItemProps = {
/** 약속 승인 아이템 데이터 */
item: MeetingApprovalItemType
/** 모임 ID */
gatheringId: number
}

/**
Expand All @@ -24,13 +26,13 @@ export type MeetingApprovalItemProps = {
* @description
* 약속 승인 리스트의 개별 아이템을 렌더링합니다.
*/
export default function MeetingApprovalItem({ item }: MeetingApprovalItemProps) {
export default function MeetingApprovalItem({ item, gatheringId }: MeetingApprovalItemProps) {
const { meetingName, bookName, nickname, startDateTime, endDateTime, meetingStatus, meetingId } =
item

const confirmMutation = useConfirmMeeting()
const rejectMutation = useRejectMeeting()
const deleteMutation = useDeleteMeeting()
const rejectMutation = useRejectMeeting(gatheringId)
const deleteMutation = useDeleteMeeting(gatheringId)
const isPending =
confirmMutation.isPending || rejectMutation.isPending || deleteMutation.isPending
const { openConfirm, openError } = useGlobalModalStore()
Expand All @@ -41,6 +43,7 @@ export default function MeetingApprovalItem({ item }: MeetingApprovalItemProps)
if (!confirmed) return

confirmMutation.mutate(meetingId, {
//Todo : 동시간에 승인할 수 없다고 별도로 알려주면 좋을듯
onError: (error) => openError('에러', error.userMessage),
})
}
Expand Down Expand Up @@ -94,7 +97,7 @@ export default function MeetingApprovalItem({ item }: MeetingApprovalItemProps)
거절
</Button>
<Button variant="primary" size="small" onClick={handleApprove} disabled={isPending}>
수락
승인
</Button>
</>
) : (
Expand Down
62 changes: 19 additions & 43 deletions src/features/meetings/components/MeetingApprovalList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,74 +3,50 @@
* @description 약속 승인 리스트 컴포넌트
*/

import { useEffect, useState } from 'react'
import { useNavigate } from 'react-router-dom'

import { MeetingApprovalItem, type MeetingStatus, useMeetingApprovals } from '@/features/meetings'
import type { PaginatedResponse } from '@/api/types'
import { MeetingApprovalItem, type MeetingApprovalItemType } from '@/features/meetings'
import { PAGE_SIZES } from '@/shared/constants'
import { Pagination } from '@/shared/ui/Pagination'
import { useGlobalModalStore } from '@/store'

export type MeetingApprovalListProps = {
/** 모임 식별자 */
/** 약속 승인 리스트 데이터 */
data: PaginatedResponse<MeetingApprovalItemType>
/** 모임 ID */
gatheringId: number
/** 약속 상태 (PENDING: 확정 대기, CONFIRMED: 확정 완료) */
status: MeetingStatus
/** 현재 페이지 */
currentPage: number
/** 페이지 변경 핸들러 */
onPageChange: (page: number) => void
}
export default function MeetingApprovalList({ gatheringId, status }: MeetingApprovalListProps) {
const navigate = useNavigate()
const [currentPage, setCurrentPage] = useState(0)
const pageSize = PAGE_SIZES.MEETING_APPROVALS
const { openError } = useGlobalModalStore()

const { data, isLoading, isError, error } = useMeetingApprovals({
gatheringId,
status,
page: currentPage,
size: pageSize,
})

useEffect(() => {
if (isError) {
openError('에러', error.userMessage, () => {
navigate('/', { replace: true })
})
}
}, [isError, openError, error, navigate])

if (isLoading) {
return (
<div className="flex items-center justify-center py-large">
<p className="typo-body3 text-grey-600">로딩 중...</p>
</div>
)
}

export default function MeetingApprovalList({
data,
gatheringId,
currentPage,
onPageChange,
}: MeetingApprovalListProps) {
if (!data || data.items.length === 0) {
return (
<div className="flex items-center justify-center py-large">
<div className="flex items-center justify-center py-large border-none mt-base">
<p className="typo-body3 text-grey-600">약속이 없습니다.</p>
</div>
)
}

const { items, totalPages, totalCount } = data
const pageSize = PAGE_SIZES.MEETING_APPROVALS
const showPagination = totalCount > pageSize

return (
<div className="flex flex-col gap-medium">
<ul>
{items.map((item) => (
<MeetingApprovalItem key={item.meetingId} item={item} />
<MeetingApprovalItem key={item.meetingId} item={item} gatheringId={gatheringId} />
))}
</ul>

{showPagination && (
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={(page: number) => setCurrentPage(page)}
/>
<Pagination currentPage={currentPage} totalPages={totalPages} onPageChange={onPageChange} />
)}
</div>
)
Expand Down
25 changes: 25 additions & 0 deletions src/features/meetings/components/MeetingApprovalListSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* @file MeetingApprovalListSkeleton.tsx
* @description 약속 승인 리스트 스켈레톤 컴포넌트
*/

export default function MeetingApprovalListSkeleton() {
const SKELETON_COUNT = 10

return (
<ul>
{[...Array(SKELETON_COUNT).keys()].map((i) => (
<li
key={i}
className="flex items-center justify-between border-b gap-medium py-large border-grey-300 last:border-b-0"
>
<div className="flex flex-col gap-xtiny flex-1">
<div className="h-5 bg-grey-200 rounded w-20 animate-pulse" />
<div className="h-5.5 bg-grey-200 rounded w-40 animate-pulse" />
<div className="h-5 bg-grey-200 rounded w-1/3 animate-pulse" />
</div>
</li>
))}
</ul>
)
}
2 changes: 1 addition & 1 deletion src/features/meetings/components/MeetingDetailButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default function MeetingDetailButton({
>
{buttonLabel}
</Button>
{isEnabled && (
{!isEnabled && (
<p className="text-grey-700 typo-body6 pt-tiny">
{type === 'EDIT_TIME_EXPIRED' && '약속 24시간 전까지만 약속 정보를 수정할 수 있어요'}
{(type === 'CANCEL_TIME_EXPIRED' || type === 'JOIN_TIME_EXPIRED') &&
Expand Down
27 changes: 11 additions & 16 deletions src/features/meetings/components/MeetingDetailInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { MapPin } from 'lucide-react'
import { useState } from 'react'

import MapModal from '@/features/meetings/components/MapModal'
import {
Avatar,
AvatarFallback,
Expand All @@ -21,8 +19,6 @@ interface MeetingDetailInfoProps {
}

export function MeetingDetailInfo({ meeting }: MeetingDetailInfoProps) {
const [isMapModalOpen, setIsMapModalOpen] = useState(false)

const leader = meeting.participants.members.find((member) => member.role === 'LEADER')
const members = meeting.participants.members.filter((member) => member.role === 'MEMBER')
const displayedMembers = members.slice(0, MAX_DISPLAYED_AVATARS)
Expand All @@ -32,6 +28,8 @@ export function MeetingDetailInfo({ meeting }: MeetingDetailInfoProps) {

const [startDate, endDate] = meeting.schedule.displayDate.split(' ~ ')

const location = meeting.location

return (
<div className="w-[300px] flex-none flex flex-col gap-base">
<div className="flex flex-col gap-medium">
Expand Down Expand Up @@ -117,28 +115,25 @@ export function MeetingDetailInfo({ meeting }: MeetingDetailInfoProps) {
<dl className="flex gap-base">
<dt className={DT_VARIANTS}>장소</dt>
<dd>
{meeting.location && (
{location && (
<TextButton
size="medium"
icon={MapPin}
className="text-black typo-body3 [&_svg]:text-grey-600"
onClick={() => setIsMapModalOpen(true)}
onClick={() => {
window.open(
`https://map.kakao.com/link/map/${location.name},${location.latitude},${location.longitude}`,
'_blank',
'noopener,noreferrer'
)
}}
>
{meeting.location.name}
{location.name}
</TextButton>
)}
</dd>
</dl>
</div>

{/* 지도 모달 */}
{meeting.location && (
<MapModal
open={isMapModalOpen}
onOpenChange={setIsMapModalOpen}
location={meeting.location}
/>
)}
</div>
)
}
2 changes: 1 addition & 1 deletion src/features/meetings/components/PlaceList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default function PlaceList({
onClick={() => onPlaceClick(place)}
onMouseEnter={() => onPlaceHover?.(place, index)}
onMouseLeave={onPlaceHoverEnd}
className="text-left transition-colors bg-white border p-small rounded-small border-grey-300 hover:bg-grey-50"
className="text-left transition-colors bg-white border p-small rounded-small border-grey-300 hover:bg-grey-50 cursor-pointer"
>
<p className="text-black typo-subtitle5 mb-xtiny">{place.place_name}</p>
<p className="typo-body4 text-grey-600 line-clamp-2">
Expand Down
Loading
Loading