feat(tickets): update TicketQueue with mapping detection, 5-item cap, View All link
All checks were successful
Mirror to GitHub / mirror (push) Successful in 4s
All checks were successful
Mirror to GitHub / mirror (push) Successful in 4s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
import { useState, useEffect, useRef, useCallback } from 'react'
|
import { useState, useEffect, useRef, useCallback } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate, Link } from 'react-router-dom'
|
||||||
import { Ticket, ChevronDown, Check, Loader2, AlertCircle } from 'lucide-react'
|
import { Ticket, ChevronDown, Check, Loader2, AlertCircle } from 'lucide-react'
|
||||||
import { integrationsApi } from '@/api/integrations'
|
import { integrationsApi } from '@/api/integrations'
|
||||||
import type { PSABoard, PSATicketSearchResult } from '@/types/integrations'
|
import type { PSABoard, PSATicketSearchResult } from '@/types/integrations'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
const PAGE_SIZE = 10
|
const PAGE_SIZE = 5
|
||||||
|
|
||||||
type Tab = 'mine' | 'unassigned'
|
type Tab = 'mine' | 'unassigned'
|
||||||
|
|
||||||
@@ -188,6 +188,7 @@ function TicketRow({ ticket, isLast, onStartSession }: TicketRowProps) {
|
|||||||
export function TicketQueue() {
|
export function TicketQueue() {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const [hasConnection, setHasConnection] = useState<boolean | null>(null)
|
const [hasConnection, setHasConnection] = useState<boolean | null>(null)
|
||||||
|
const [hasMemberMapping, setHasMemberMapping] = useState<boolean | null>(null) // null = loading
|
||||||
const [boards, setBoards] = useState<PSABoard[]>([])
|
const [boards, setBoards] = useState<PSABoard[]>([])
|
||||||
const [selectedBoardIds, setSelectedBoardIds] = useState<number[]>([])
|
const [selectedBoardIds, setSelectedBoardIds] = useState<number[]>([])
|
||||||
const [activeTab, setActiveTab] = useState<Tab>('mine')
|
const [activeTab, setActiveTab] = useState<Tab>('mine')
|
||||||
@@ -208,6 +209,15 @@ export function TicketQueue() {
|
|||||||
.catch(() => setHasConnection(false))
|
.catch(() => setHasConnection(false))
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Detect member mapping on mount
|
||||||
|
useEffect(() => {
|
||||||
|
integrationsApi.getMemberMappings()
|
||||||
|
.then(mappings => {
|
||||||
|
setHasMemberMapping(mappings.length > 0)
|
||||||
|
})
|
||||||
|
.catch(() => setHasMemberMapping(false))
|
||||||
|
}, [])
|
||||||
|
|
||||||
// Fetch boards once connection confirmed
|
// Fetch boards once connection confirmed
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!hasConnection) return
|
if (!hasConnection) return
|
||||||
@@ -250,12 +260,13 @@ export function TicketQueue() {
|
|||||||
// Initial + reset fetch when tab or board selection changes
|
// Initial + reset fetch when tab or board selection changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!hasConnection) return
|
if (!hasConnection) return
|
||||||
|
if (activeTab === 'mine' && hasMemberMapping !== true) return
|
||||||
setPage(1)
|
setPage(1)
|
||||||
setTickets([])
|
setTickets([])
|
||||||
setHasMore(false)
|
setHasMore(false)
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
fetchTickets(activeTab, selectedBoardIds, 1, false).finally(() => setLoading(false))
|
fetchTickets(activeTab, selectedBoardIds, 1, false).finally(() => setLoading(false))
|
||||||
}, [activeTab, selectedBoardIds, hasConnection, fetchTickets])
|
}, [activeTab, selectedBoardIds, hasConnection, hasMemberMapping, fetchTickets])
|
||||||
|
|
||||||
const handleLoadMore = async () => {
|
const handleLoadMore = async () => {
|
||||||
const nextPage = page + 1
|
const nextPage = page + 1
|
||||||
@@ -327,6 +338,18 @@ export function TicketQueue() {
|
|||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div>
|
<div>
|
||||||
|
{/* Mapping prompt for "mine" tab when no member mapping configured */}
|
||||||
|
{activeTab === 'mine' && hasMemberMapping === false && (
|
||||||
|
<div className="px-5 py-6 text-center">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
<Link to="/account/integrations" className="text-accent hover:underline">
|
||||||
|
Map your PSA member
|
||||||
|
</Link>{' '}
|
||||||
|
to see your ticket queue.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Error */}
|
{/* Error */}
|
||||||
{error && (
|
{error && (
|
||||||
<div className="flex items-center gap-2 px-5 py-4 text-sm text-danger">
|
<div className="flex items-center gap-2 px-5 py-4 text-sm text-danger">
|
||||||
@@ -352,6 +375,18 @@ export function TicketQueue() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* View all tickets link */}
|
||||||
|
{tickets.length > 0 && (
|
||||||
|
<div className="px-5 py-3 border-t border-default">
|
||||||
|
<Link
|
||||||
|
to="/tickets?assigned=me"
|
||||||
|
className="text-xs text-accent hover:text-accent/80 transition-colors"
|
||||||
|
>
|
||||||
|
View all tickets →
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Empty states */}
|
{/* Empty states */}
|
||||||
{!error && !loading && tickets.length === 0 && (
|
{!error && !loading && tickets.length === 0 && (
|
||||||
<div className="px-5 py-8 text-center">
|
<div className="px-5 py-8 text-center">
|
||||||
|
|||||||
Reference in New Issue
Block a user