close ticket
This commit is contained in:
@@ -1,12 +1,11 @@
|
||||
import { type FC, useMemo, useState } from "react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { useParams } from "react-router-dom";
|
||||
import Input from "@/components/Input";
|
||||
import { Paths } from "@/config/Paths";
|
||||
import { clx } from "@/helpers/utils";
|
||||
import { t } from "@/locale";
|
||||
import { getTicketDisplayName } from "./types/TicketTypes";
|
||||
import type { TicketDetailType } from "./types/TicketTypes";
|
||||
import { useCreateOrReplyTicket, useGetTicketById } from "./hooks/useTicketData";
|
||||
import { useCloseTicket, useCreateOrReplyTicket, useGetTicketById } from "./hooks/useTicketData";
|
||||
import { buildThreadItems, getStatusClass } from "./detailUtils";
|
||||
import MessageBubble from "./MessageBubble";
|
||||
import ReplyForm from "./ReplyForm";
|
||||
@@ -16,13 +15,13 @@ import TicketDetailActions from "./TicketDetailActions";
|
||||
const STATUS_CLOSED = "closed";
|
||||
|
||||
const TicketDetail: FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { id } = useParams<{ id: string }>();
|
||||
const [content, setContent] = useState("");
|
||||
const [files, setFiles] = useState<File[]>([]);
|
||||
|
||||
const getTicket = useGetTicketById(id ?? "");
|
||||
const addMessage = useCreateOrReplyTicket();
|
||||
const closeTicket = useCloseTicket();
|
||||
|
||||
const ticket = getTicket.data?.data;
|
||||
const threadItems = useMemo(
|
||||
@@ -33,7 +32,15 @@ const TicketDetail: FC = () => {
|
||||
ticket?.status?.toLowerCase() === STATUS_CLOSED ||
|
||||
ticket?.status?.toUpperCase() === "CLOSED";
|
||||
|
||||
const handleCloseTicket = () => navigate(Paths.tickets.list);
|
||||
const handleCloseTicket = () => {
|
||||
if (!id) return;
|
||||
closeTicket.mutate(
|
||||
{ id, params: { status: "closed" } },
|
||||
{
|
||||
onSuccess: () => getTicket.refetch(),
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const handleSendReply = () => {
|
||||
if (!id || !ticket || !content.trim()) return;
|
||||
@@ -146,6 +153,7 @@ const TicketDetail: FC = () => {
|
||||
<TicketDetailActions
|
||||
onScrollToReply={handleScrollToReply}
|
||||
onCloseTicket={handleCloseTicket}
|
||||
isClosing={closeTicket.isPending}
|
||||
/>
|
||||
)}
|
||||
<TicketInfoSidebar ticket={ticket} />
|
||||
|
||||
@@ -6,11 +6,13 @@ import { t } from "@/locale";
|
||||
export type TicketDetailActionsProps = {
|
||||
onScrollToReply: () => void;
|
||||
onCloseTicket: () => void;
|
||||
isClosing?: boolean;
|
||||
};
|
||||
|
||||
const TicketDetailActions: FC<TicketDetailActionsProps> = ({
|
||||
onScrollToReply,
|
||||
onCloseTicket,
|
||||
isClosing = false,
|
||||
}) => (
|
||||
<div className="bg-white xl:p-6 p-4 rounded-3xl flex gap-4">
|
||||
<Button
|
||||
@@ -21,10 +23,11 @@ const TicketDetailActions: FC<TicketDetailActionsProps> = ({
|
||||
<Button
|
||||
className="bg-[#D52903] xl:h-10 h-8"
|
||||
onClick={onCloseTicket}
|
||||
disabled={isClosing}
|
||||
>
|
||||
<div className="flex gap-2 text-xs items-center text-white">
|
||||
<CloseCircle color="white" size={20} />
|
||||
<span>{t("ticket.close_ticket")}</span>
|
||||
<span>{isClosing ? "..." : t("ticket.close_ticket")}</span>
|
||||
</div>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import * as api from "../service/TicketService";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { type AddMessageTicketType, type CreateTicketPayload, type CreateTicketType } from "../types/TicketTypes";
|
||||
import {
|
||||
type AddMessageTicketType,
|
||||
type CloseTicketParamsType,
|
||||
type CreateTicketPayload,
|
||||
type CreateTicketType,
|
||||
} from "../types/TicketTypes";
|
||||
|
||||
export const useGetTickets = (status?: string) => {
|
||||
return useQuery({
|
||||
@@ -82,7 +87,13 @@ export const useAddMessageTicket = (id: string) => {
|
||||
export const useCloseTicket = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => api.closeTicket(id),
|
||||
mutationFn: ({
|
||||
id,
|
||||
params,
|
||||
}: {
|
||||
id: string;
|
||||
params: CloseTicketParamsType;
|
||||
}) => api.closeTicket(id, params),
|
||||
onSuccess: () => {
|
||||
queryClient.refetchQueries({
|
||||
queryKey: ["tickets"],
|
||||
|
||||
@@ -2,6 +2,7 @@ import type { AxiosProgressEvent } from "axios";
|
||||
import axios from "@/config/axios";
|
||||
import {
|
||||
type AddMessageTicketType,
|
||||
type CloseTicketParamsType,
|
||||
type CreateTicketPayload,
|
||||
type CreateTicketType,
|
||||
type GetTicketByIdResponseType,
|
||||
@@ -92,7 +93,7 @@ export const addMessageTicket = async (
|
||||
return data;
|
||||
};
|
||||
|
||||
export const closeTicket = async (id: string) => {
|
||||
const { data } = await axios.post(`/tickets/${id}/close`);
|
||||
export const closeTicket = async (id: string, params: CloseTicketParamsType) => {
|
||||
const { data } = await axios.patch(`/public/tickets/${id}/status`, params);
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -32,7 +32,10 @@ export type TicketListItemType = {
|
||||
export type GetTicketsResponseType = BaseResponse<TicketListItemType[]>;
|
||||
|
||||
/** آیتم تیکت در children (user بهصورت id یا null، admin برای تشخیص پیام ادمین/کاربر) */
|
||||
export type TicketDetailChildType = Omit<TicketListItemType, "user" | "children"> & {
|
||||
export type TicketDetailChildType = Omit<
|
||||
TicketListItemType,
|
||||
"user" | "children"
|
||||
> & {
|
||||
user: string | null;
|
||||
/** null = پیام از کاربر، مقدار دارد = پیام از ادمین/کارشناس */
|
||||
admin: string | null;
|
||||
@@ -96,4 +99,10 @@ export type TicketThreadItemType = {
|
||||
};
|
||||
|
||||
export const getTicketDisplayName = (user: TicketUserType): string =>
|
||||
[user.firstName, user.lastName].filter(Boolean).join(" ").trim() || user.phone || "-";
|
||||
[user.firstName, user.lastName].filter(Boolean).join(" ").trim() ||
|
||||
user.phone ||
|
||||
"-";
|
||||
|
||||
export type CloseTicketParamsType = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user