analytica-frontend-lib
Version:
Repositório público dos componentes utilizados nas plataformas da Analytica Ensino
1 lines • 33.4 kB
Source Map (JSON)
{"version":3,"sources":["../src/components/Support/Support.tsx","../src/components/Support/schema/index.ts"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport { useForm } from 'react-hook-form';\nimport { zodResolver } from '@hookform/resolvers/zod';\nimport {\n KeyIcon,\n InfoIcon,\n BugIcon,\n CaretRightIcon,\n} from '@phosphor-icons/react';\nimport dayjs from 'dayjs';\nimport Text from '../Text/Text';\nimport SelectionButton from '../SelectionButton/SelectionButton';\nimport Input from '../Input/Input';\nimport TextArea from '../TextArea/TextArea';\nimport Button from '../Button/Button';\nimport Select, {\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '../Select/Select';\nimport Badge from '../Badge/Badge';\nimport { SkeletonText, SkeletonRounded } from '../Skeleton/Skeleton';\nimport Toast from '../Toast/Toast';\nimport Menu, { MenuContent, MenuItem } from '../Menu/Menu';\nimport { supportSchema, SupportFormData } from './schema';\nimport { TicketModal } from './components/TicketModal';\nimport {\n SupportTicket,\n SupportStatus,\n SupportCategory,\n TabType,\n ProblemType,\n getStatusBadgeAction,\n getStatusText,\n getCategoryText,\n CreateSupportTicketRequest,\n CreateSupportTicketResponse,\n SupportTicketAPI,\n GetSupportTicketsResponse,\n mapApiStatusToInternal,\n mapInternalStatusToApi,\n SupportApiClient,\n} from '../../types/support';\nimport { getCategoryIcon } from './utils/supportUtils';\nimport SupportImage from '../../assets/img/suporthistory.png';\n\n// Individual ticket component to reduce nesting\nconst TicketCard = ({\n ticket,\n onTicketClick,\n}: {\n ticket: SupportTicket;\n onTicketClick: (ticket: SupportTicket) => void;\n}) => (\n <button\n key={ticket.id}\n type=\"button\"\n className=\"flex items-center justify-between p-4 bg-background rounded-xl cursor-pointer w-full text-left hover:bg-background-50 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2\"\n onClick={() => onTicketClick(ticket)}\n >\n <div className=\"flex flex-col\">\n <Text size=\"xs\" weight=\"bold\" className=\"text-text-900\">\n {ticket.title}\n </Text>\n </div>\n\n <div className=\"flex items-center gap-3\">\n <Badge\n variant=\"solid\"\n className=\"flex items-center gap-1\"\n action={getStatusBadgeAction(ticket.status)}\n >\n {getStatusText(ticket.status)}\n </Badge>\n <Badge variant=\"solid\" className=\"flex items-center gap-1\" action=\"muted\">\n {getCategoryIcon(ticket.category, 18)}\n {getCategoryText(ticket.category)}\n </Badge>\n <CaretRightIcon size={24} className=\"text-text-800\" />\n </div>\n </button>\n);\n\n// Ticket group component to reduce nesting\nconst TicketGroup = ({\n date,\n tickets,\n onTicketClick,\n}: {\n date: string;\n tickets: SupportTicket[];\n onTicketClick: (ticket: SupportTicket) => void;\n}) => (\n <div key={date} className=\"space-y-4\">\n <Text size=\"md\" weight=\"bold\" className=\"text-text-900\">\n {dayjs(date).format('DD MMM YYYY')}\n </Text>\n <div className=\"space-y-3\">\n {tickets.map((ticket) => (\n <TicketCard\n key={ticket.id}\n ticket={ticket}\n onTicketClick={onTicketClick}\n />\n ))}\n </div>\n </div>\n);\n\n// Empty state component\nconst EmptyState = ({ imageSrc }: { imageSrc?: string }) => (\n <div className=\"flex flex-row justify-center items-center mt-48\">\n {imageSrc && <img src={imageSrc} alt=\"Imagem de suporte\" />}\n <Text size=\"3xl\" weight=\"semibold\">\n Nenhum pedido encontrado.\n </Text>\n </div>\n);\n\n// Skeleton component for ticket loading\nconst TicketSkeleton = () => (\n <div className=\"space-y-6\">\n {[0, 1].map((groupIndex) => (\n <div key={groupIndex} className=\"space-y-4\">\n {/* Date skeleton */}\n <SkeletonText width=\"150px\" height={20} />\n\n {/* Tickets skeleton */}\n <div className=\"space-y-3\">\n {[0, 1].map((ticketIndex) => (\n <SkeletonRounded\n key={ticketIndex}\n width=\"100%\"\n height={72}\n className=\"p-4\"\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n);\n\nexport interface SupportProps {\n /** API client instance for making requests */\n apiClient: SupportApiClient;\n /** Current user ID */\n userId?: string;\n /** Custom empty state image source (optional, uses default if not provided) */\n emptyStateImage?: string;\n /** Title displayed in the header */\n title?: string;\n /** Callback when a ticket is successfully created */\n onTicketCreated?: () => void;\n /** Callback when a ticket is successfully closed */\n onTicketClosed?: () => void;\n}\n\nconst Support = ({\n apiClient,\n userId,\n emptyStateImage,\n title = 'Suporte',\n onTicketCreated,\n onTicketClosed,\n}: SupportProps) => {\n const [activeTab, setActiveTab] = useState<TabType>('criar-pedido');\n const [selectedProblem, setSelectedProblem] = useState<ProblemType>(null);\n\n // Filtros do histórico\n const [statusFilter, setStatusFilter] = useState<string>('todos');\n const [categoryFilter, setCategoryFilter] = useState<string>('todos');\n\n // Estado do modal\n const [selectedTicket, setSelectedTicket] = useState<SupportTicket | null>(\n null\n );\n const [isModalOpen, setIsModalOpen] = useState(false);\n\n // Estados para feedback\n const [submitError, setSubmitError] = useState<string | null>(null);\n const [showSuccessToast, setShowSuccessToast] = useState(false);\n const [showCloseSuccessToast, setShowCloseSuccessToast] = useState(false);\n const [showCloseErrorToast, setShowCloseErrorToast] = useState(false);\n\n // Estados para histórico\n const [allTickets, setAllTickets] = useState<SupportTicketAPI[]>([]);\n const [loadingTickets, setLoadingTickets] = useState(false);\n const [currentPage, setCurrentPage] = useState(1);\n const ITEMS_PER_PAGE = 10;\n\n // Pagination handlers\n const handlePrevPage = () => {\n if (currentPage > 1) {\n setCurrentPage(currentPage - 1);\n }\n };\n\n const handleNextPage = () => {\n const totalPages = Math.ceil(filteredTickets.length / ITEMS_PER_PAGE);\n if (currentPage < totalPages) {\n setCurrentPage(currentPage + 1);\n }\n };\n\n // useEffect para buscar tickets quando mudar aba ou filtros\n useEffect(() => {\n if (activeTab === 'historico') {\n fetchTickets(statusFilter);\n setCurrentPage(1); // Reset to first page when filters change\n }\n }, [activeTab, statusFilter]);\n\n // Reset page when category filter changes\n useEffect(() => {\n setCurrentPage(1);\n }, [categoryFilter]);\n\n // Funções auxiliares\n\n // Converter dados da API para formato do componente\n const convertApiTicketToComponent = (\n apiTicket: SupportTicketAPI\n ): SupportTicket => {\n return {\n id: apiTicket.id,\n title: apiTicket.subject,\n status: mapApiStatusToInternal(apiTicket.status),\n createdAt: apiTicket.createdAt,\n category: apiTicket.type as SupportCategory,\n description: apiTicket.description,\n };\n };\n\n // Filtrar tickets por categoria e ordenar do mais novo para o mais antigo\n const filteredTickets = allTickets\n .map(convertApiTicketToComponent)\n .filter((ticket) => {\n const categoryMatch =\n categoryFilter === 'todos' || ticket.category === categoryFilter;\n return categoryMatch;\n })\n .sort(\n (a, b) =>\n new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()\n );\n\n // Calcular paginação no frontend\n const totalPages = Math.ceil(filteredTickets.length / ITEMS_PER_PAGE);\n const startIndex = (currentPage - 1) * ITEMS_PER_PAGE;\n const endIndex = startIndex + ITEMS_PER_PAGE;\n const paginatedTickets = filteredTickets.slice(startIndex, endIndex);\n\n const groupedTickets = paginatedTickets.reduce(\n (groups, ticket) => {\n const date = dayjs(ticket.createdAt).format('YYYY-MM-DD');\n if (!groups[date]) {\n groups[date] = [];\n }\n groups[date].push(ticket);\n return groups;\n },\n {} as Record<string, SupportTicket[]>\n );\n\n // React Hook Form setup\n const {\n register,\n handleSubmit,\n setValue,\n reset,\n formState: { errors, isSubmitting },\n } = useForm<SupportFormData>({\n resolver: zodResolver(supportSchema),\n defaultValues: {\n problemType: undefined,\n title: '',\n description: '',\n },\n });\n\n // Fetch tickets from API - buscar todos de uma vez com limit=100\n const fetchTickets = async (status?: string) => {\n setLoadingTickets(true);\n try {\n const params = new URLSearchParams({\n page: '1',\n limit: '100', // Buscar o máximo permitido pela API\n });\n\n if (status && status !== 'todos') {\n // Convert internal status to API status\n const apiStatus = mapInternalStatusToApi(status as SupportStatus);\n params.append('status', apiStatus);\n }\n\n const response = await apiClient.get<GetSupportTicketsResponse>(\n `/support?${params.toString()}`\n );\n\n setAllTickets(response.data.data.support);\n } catch (error) {\n console.error('Erro ao buscar tickets:', error);\n setAllTickets([]);\n } finally {\n setLoadingTickets(false);\n }\n };\n\n // Handle problem type selection\n const handleProblemSelection = (type: ProblemType) => {\n setSelectedProblem(type);\n if (type) {\n setValue('problemType', type, { shouldValidate: true });\n }\n };\n\n // Handle form submission\n const onSubmit = async (data: SupportFormData) => {\n setSubmitError(null);\n\n try {\n const requestData: CreateSupportTicketRequest = {\n subject: data.title,\n description: data.description,\n type: data.problemType,\n };\n\n await apiClient.post<CreateSupportTicketResponse>(\n '/support',\n requestData\n );\n\n // Show success toast\n setShowSuccessToast(true);\n setTimeout(() => setShowSuccessToast(false), 4000);\n\n // Reset form after successful submission\n setSelectedProblem(null);\n reset();\n\n // Switch to history tab and refresh tickets list\n setActiveTab('historico');\n fetchTickets(statusFilter);\n\n // Call callback if provided\n onTicketCreated?.();\n } catch (error) {\n console.error('Erro ao criar ticket de suporte:', error);\n setSubmitError('Erro ao criar ticket. Tente novamente.');\n }\n };\n\n // Handle ticket click\n const handleTicketClick = (ticket: SupportTicket) => {\n setSelectedTicket(ticket);\n setIsModalOpen(true);\n };\n\n // Handle modal close\n const handleModalClose = () => {\n setIsModalOpen(false);\n setSelectedTicket(null);\n };\n\n // Handle ticket close\n const handleTicketClose = async (ticketId: string) => {\n try {\n await apiClient.patch(`/support/${ticketId}`, {\n status: mapInternalStatusToApi(SupportStatus.ENCERRADO),\n });\n\n // Show success toast\n setShowCloseSuccessToast(true);\n setTimeout(() => setShowCloseSuccessToast(false), 4000);\n\n // Refresh tickets list\n if (activeTab === 'historico') {\n fetchTickets(statusFilter);\n }\n\n // Call callback if provided\n onTicketClosed?.();\n } catch (error) {\n console.error('Erro ao encerrar ticket:', error);\n // Show error toast\n setShowCloseErrorToast(true);\n setTimeout(() => setShowCloseErrorToast(false), 4000);\n }\n };\n\n const problemTypes = [\n {\n id: SupportCategory.TECNICO,\n title: 'Técnico',\n icon: <BugIcon size={24} />,\n },\n {\n id: SupportCategory.ACESSO,\n title: 'Acesso',\n icon: <KeyIcon size={24} />,\n },\n {\n id: SupportCategory.OUTROS,\n title: 'Outros',\n icon: <InfoIcon size={24} />,\n },\n ];\n\n // Determine which image to use for empty state\n const emptyImage = emptyStateImage || SupportImage;\n\n return (\n <div className=\"flex flex-col w-full h-full overflow-y-auto\">\n <div className=\"flex flex-col w-full h-full\">\n {/* Header */}\n <div className=\"space-y-4\">\n <div className=\"flex w-full mb-4 flex-row items-center justify-between not-lg:gap-4 lg:gap-6\">\n <h1 className=\"font-bold leading-[28px] tracking-[0.2px] text-text-950 text-xl mt-4 sm:text-2xl sm:flex-1 sm:self-end sm:mt-0\">\n {title}\n </h1>\n <div className=\"sm:flex-shrink-0 sm:self-end\">\n <Menu\n value={activeTab}\n defaultValue=\"criar-pedido\"\n variant=\"menu2\"\n onValueChange={(value) => setActiveTab(value as TabType)}\n className=\"bg-transparent shadow-none px-0\"\n >\n <MenuContent variant=\"menu2\">\n <MenuItem\n variant=\"menu2\"\n value=\"criar-pedido\"\n className=\"whitespace-nowrap px-17 not-sm:px-5\"\n >\n Criar Pedido\n </MenuItem>\n <MenuItem\n variant=\"menu2\"\n value=\"historico\"\n className=\"whitespace-nowrap px-17 not-sm:px-5\"\n >\n Histórico\n </MenuItem>\n </MenuContent>\n </Menu>\n </div>\n </div>\n\n {/* Content for Criar Pedido tab */}\n {activeTab === 'criar-pedido' && (\n <div className=\"space-y-2\">\n <Text as=\"h2\" size=\"md\" weight=\"bold\" className=\"text-text-900\">\n Selecione o tipo de problema\n </Text>\n\n <div className=\"flex flex-col sm:flex-row gap-2 sm:gap-4\">\n {problemTypes.map((type) => (\n <SelectionButton\n key={type.id}\n icon={type.icon}\n label={type.title}\n selected={selectedProblem === type.id}\n onClick={() => handleProblemSelection(type.id)}\n className=\"w-full p-4\"\n />\n ))}\n </div>\n {errors.problemType && (\n <Text size=\"sm\" className=\"text-red-500 mt-1\">\n {errors.problemType.message}\n </Text>\n )}\n </div>\n )}\n\n {selectedProblem && activeTab === 'criar-pedido' && (\n <form onSubmit={handleSubmit(onSubmit)} className=\"space-y-4\">\n <div className=\"space-y-1\">\n <Input\n size=\"large\"\n variant=\"rounded\"\n label=\"Título\"\n placeholder=\"Digite o título\"\n {...register('title')}\n errorMessage={errors.title?.message}\n />\n </div>\n <div className=\"space-y-1\">\n <TextArea\n size=\"large\"\n label=\"Descrição\"\n placeholder=\"Descreva o problema aqui\"\n {...register('description')}\n errorMessage={errors.description?.message}\n />\n </div>\n <Button\n size=\"large\"\n className=\"float-end mt-10\"\n type=\"submit\"\n disabled={isSubmitting}\n >\n {isSubmitting ? 'Enviando...' : 'Enviar Pedido'}\n </Button>\n\n {/* Error message */}\n {submitError && (\n <div className=\"mt-4 p-4 bg-red-100 border border-red-400 text-red-700 rounded\">\n <Text size=\"sm\" className=\"text-red-700\">\n {submitError}\n </Text>\n </div>\n )}\n </form>\n )}\n\n {/* Content for Historico tab */}\n {activeTab === 'historico' && (\n <div className=\"space-y-6\">\n {/* Filtros */}\n <div className=\"flex gap-4\">\n <div className=\"flex flex-col flex-1/2 space-y-1\">\n <Select\n label=\"Status\"\n size=\"large\"\n value={statusFilter}\n onValueChange={setStatusFilter}\n >\n <SelectTrigger variant=\"rounded\" className=\"\">\n <SelectValue placeholder=\"Todos\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"todos\">Todos</SelectItem>\n <SelectItem value={SupportStatus.ABERTO}>\n Aberto\n </SelectItem>\n <SelectItem value={SupportStatus.RESPONDIDO}>\n Respondido\n </SelectItem>\n <SelectItem value={SupportStatus.ENCERRADO}>\n Encerrado\n </SelectItem>\n </SelectContent>\n </Select>\n </div>\n\n <div className=\"flex flex-col flex-1/2 space-y-1\">\n <Select\n label=\"Tipo\"\n size=\"large\"\n value={categoryFilter}\n onValueChange={setCategoryFilter}\n >\n <SelectTrigger variant=\"rounded\" className=\"\">\n <SelectValue placeholder=\"Todos\" />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"todos\">Todos</SelectItem>\n <SelectItem value={SupportCategory.TECNICO}>\n <BugIcon size={16} /> Técnico\n </SelectItem>\n <SelectItem value={SupportCategory.ACESSO}>\n <KeyIcon size={16} /> Acesso\n </SelectItem>\n <SelectItem value={SupportCategory.OUTROS}>\n <InfoIcon size={16} /> Outros\n </SelectItem>\n </SelectContent>\n </Select>\n </div>\n </div>\n\n {/* Lista de tickets */}\n {(() => {\n if (loadingTickets) {\n return <TicketSkeleton />;\n }\n\n if (Object.keys(groupedTickets).length === 0) {\n return <EmptyState imageSrc={emptyImage} />;\n }\n\n return (\n <div className=\"space-y-6\">\n {Object.entries(groupedTickets)\n .sort(\n ([a], [b]) =>\n new Date(b).getTime() - new Date(a).getTime()\n )\n .map(([date, tickets]) => (\n <TicketGroup\n key={date}\n date={date}\n tickets={tickets}\n onTicketClick={handleTicketClick}\n />\n ))}\n </div>\n );\n })()}\n\n {/* Paginação */}\n {!loadingTickets && totalPages > 1 && (\n <div className=\"flex justify-center items-center gap-4 mt-6\">\n <Button\n variant=\"outline\"\n size=\"small\"\n onClick={handlePrevPage}\n disabled={currentPage === 1}\n >\n Anterior\n </Button>\n <Text size=\"sm\" className=\"text-text-600\">\n Página {currentPage} de {totalPages}\n </Text>\n <Button\n variant=\"outline\"\n size=\"small\"\n onClick={handleNextPage}\n disabled={currentPage === totalPages}\n >\n Próxima\n </Button>\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n\n {/* Modal do ticket */}\n {selectedTicket && (\n <TicketModal\n ticket={selectedTicket}\n isOpen={isModalOpen}\n onClose={handleModalClose}\n onTicketClose={handleTicketClose}\n apiClient={apiClient}\n userId={userId}\n />\n )}\n\n {/* Success Toast */}\n {showSuccessToast && (\n <div className=\"fixed top-4 left-1/2 transform -translate-x-1/2 z-50\">\n <Toast\n title=\"Pedido enviado!\"\n description=\"Agora você pode acompanhar o andamento do seu pedido.\"\n variant=\"solid\"\n onClose={() => setShowSuccessToast(false)}\n />\n </div>\n )}\n\n {/* Close Success Toast */}\n {showCloseSuccessToast && (\n <div className=\"fixed top-4 left-1/2 transform -translate-x-1/2 z-50\">\n <Toast\n title=\"Pedido encerrado!\"\n description=\"\"\n variant=\"solid\"\n onClose={() => setShowCloseSuccessToast(false)}\n />\n </div>\n )}\n\n {/* Close Error Toast */}\n {showCloseErrorToast && (\n <div className=\"fixed top-4 left-1/2 transform -translate-x-1/2 z-50\">\n <Toast\n title=\"Erro ao encerrar pedido\"\n description=\"Não foi possível encerrar o pedido. Tente novamente.\"\n variant=\"solid\"\n action=\"warning\"\n onClose={() => setShowCloseErrorToast(false)}\n />\n </div>\n )}\n </div>\n );\n};\n\nexport default Support;\n","import { z } from 'zod';\n\n// Schema de validação para o formulário de suporte\nexport const supportSchema = z.object({\n // Tipo de problema selecionado\n problemType: z.enum(['tecnico', 'acesso', 'outros'], {\n error: () =>\n 'Campo obrigatório! Por favor, preencha este campo para continuar.',\n }),\n\n // Título do problema\n title: z\n .string()\n .min(1, 'Campo obrigatório! Por favor, preencha este campo para continuar.')\n .min(5, 'Título deve ter pelo menos 5 caracteres')\n .max(100, 'Título deve ter no máximo 100 caracteres')\n .trim(),\n\n // Descrição do problema\n description: z\n .string()\n .min(1, 'Campo obrigatório! Por favor, preencha este campo para continuar.')\n .min(10, 'Descrição deve ter pelo menos 10 caracteres')\n .max(1000, 'Descrição deve ter no máximo 1000 caracteres')\n .trim(),\n});\n\n// Type inferido do schema\nexport type SupportFormData = z.infer<typeof supportSchema>;\n"],"mappings":"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","names":["totalPages"]}