diff --git a/dump.rdb b/dump.rdb deleted file mode 100644 index 7c4e74d..0000000 Binary files a/dump.rdb and /dev/null differ diff --git a/src/app/tenders/feedback/[id]/page.tsx b/src/app/tenders/feedback/[id]/page.tsx new file mode 100644 index 0000000..60c1f9a --- /dev/null +++ b/src/app/tenders/feedback/[id]/page.tsx @@ -0,0 +1,28 @@ +"use client"; +import Breadcrumb from "@/components/Breadcrumbs/Breadcrumb"; +import TenderFeedbackTable from "@/components/Tables/tenders/feedback"; +import { BreadcrumbItem } from "@/types/shared"; +import { use } from "react"; +interface IProps { + params: Promise<{ + id: string; + }>; +} + +const TenderFeedbackPage = ({ params }: IProps) => { + const { id } = use(params); + + const breadcrumbItems: BreadcrumbItem[] = [ + { href: "/", name: "Dashboard" }, + { href: "/tenders", name: "Tenders" }, + { href: `/tenders/feedback/${id}`, name: "Tender feedback" }, + ]; + return ( + <> + + + + ); +}; + +export default TenderFeedbackPage; diff --git a/src/assets/icons.tsx b/src/assets/icons.tsx index 7c3406b..4b3433d 100644 --- a/src/assets/icons.tsx +++ b/src/assets/icons.tsx @@ -297,7 +297,20 @@ export function EmailIcon(props: IconProps) { ); } - +export function FeedbackIcon(props: IconProps) { + return ( + + + + ); +} export function PasswordIcon(props: IconProps) { return ( { + const { feedback, isLoading, columns, pathName, router } = + useTenderFeedbackPresenter({ id }); + return ( +
+ + + + {columns.map((column) => ( + + {column} + + ))} + + + {isLoading && } + + {feedback?.map((item, index) => + !item ? ( +
No feedback is submitted for this tender
+ ) : ( + + + {index + 1} + + + {item.feedback_type} + + + {unixToDate(item.updated_at)} + + + {item?.tender?.title ?? "-"} + + + {unixToDate(item.created_at)} + + + + + + ), + )} +
+
+
+ ); +}; + +export default TenderFeedbackTable; diff --git a/src/components/Tables/tenders/feedback/useTenderFeedbackPresenter.ts b/src/components/Tables/tenders/feedback/useTenderFeedbackPresenter.ts new file mode 100644 index 0000000..07fbec3 --- /dev/null +++ b/src/components/Tables/tenders/feedback/useTenderFeedbackPresenter.ts @@ -0,0 +1,20 @@ +"use client"; +import { useGetFeedback } from "@/hooks/queries"; +import { usePathname, useRouter } from "next/navigation"; + +const useTenderFeedbackPresenter = ({ id }: { id: string }) => { + const { data, isLoading } = useGetFeedback({ tender_id: id }); + const router = useRouter(); + const pathName = usePathname(); + const columns = [ + "row", + "feedback type", + "updated at", + "tender name", + "created at", + "actions", + ]; + return { feedback: data?.data, isLoading, columns, pathName, router }; +}; + +export default useTenderFeedbackPresenter; diff --git a/src/components/Tables/tenders/index.tsx b/src/components/Tables/tenders/index.tsx index ebd76b4..3518cba 100644 --- a/src/components/Tables/tenders/index.tsx +++ b/src/components/Tables/tenders/index.tsx @@ -11,7 +11,7 @@ import { } from "@/components/ui/table"; import useTenderListPresenter from "./useTenderListPresenter"; -import { ExclamationIcon } from "@/assets/icons"; +import { ExclamationIcon, FeedbackIcon } from "@/assets/icons"; import Pagination from "@/components/ui/pagination"; import TableSkeleton from "@/components/ui/TableSkeleton"; import { cn } from "@/lib/utils"; @@ -65,7 +65,10 @@ const TendersTable = () => { {item.status} - + + ), diff --git a/src/components/forms/companies/CreateCompany.tsx b/src/components/forms/companies/CreateCompany.tsx index d4d9793..51c8992 100644 --- a/src/components/forms/companies/CreateCompany.tsx +++ b/src/components/forms/companies/CreateCompany.tsx @@ -528,7 +528,6 @@ const CreateCompany = ({ defaultValues, editMode, id }: IProps) => { - ); }; diff --git a/src/hooks/queries/index.ts b/src/hooks/queries/index.ts index 5443ab8..08dff37 100644 --- a/src/hooks/queries/index.ts +++ b/src/hooks/queries/index.ts @@ -3,3 +3,4 @@ export * from "./useCompaniesQueries"; export * from "./useTenders"; export * from "./useCustomerQueries"; export * from "./useProfileQueries"; +export * from "./useFeedbackQueries" \ No newline at end of file diff --git a/src/hooks/queries/useCompaniesQueries.ts b/src/hooks/queries/useCompaniesQueries.ts index 4fa96dd..e8ab92a 100644 --- a/src/hooks/queries/useCompaniesQueries.ts +++ b/src/hooks/queries/useCompaniesQueries.ts @@ -45,6 +45,9 @@ export const useUpdateCompany = (id: string) => { queryClient.invalidateQueries({ queryKey: [API_ENDPOINTS.COMPANIES.READ_ALL], }); + queryClient.invalidateQueries({ + queryKey: [API_ENDPOINTS.COMPANIES.READ_ALL, "details"], + }); router.push("/companies"); }, }); @@ -52,7 +55,7 @@ export const useUpdateCompany = (id: string) => { export const useCompanyDetails = (id: string) => { const queryKey = useMemo( - () => [API_ENDPOINTS.COMPANIES.DETAILS(id), "details"], + () => [API_ENDPOINTS.COMPANIES.READ_ALL, "details"], [id], ); return useQuery({ diff --git a/src/hooks/queries/useFeedbackQueries.ts b/src/hooks/queries/useFeedbackQueries.ts new file mode 100644 index 0000000..31dcec0 --- /dev/null +++ b/src/hooks/queries/useFeedbackQueries.ts @@ -0,0 +1,22 @@ +import { API_ENDPOINTS } from "@/lib/api"; +import { feedbackService } from "@/lib/api/services/feedback-service"; +import { useQuery } from "@tanstack/react-query"; +import { useMemo } from "react"; + +export const useGetFeedSingleFeedback = (id: string) => { + const queryKey = useMemo(() => [API_ENDPOINTS.FEEDBACK.DETAILS(id)], [id]); + return useQuery({ + queryKey, + queryFn: () => feedbackService.getSingleFeedback(id), + }); +}; +export const useGetFeedback = (params: Record) => { + const queryKey = useMemo( + () => [API_ENDPOINTS.FEEDBACK.READ_ALL, params], + [params], + ); + return useQuery({ + queryKey, + queryFn: () => feedbackService.getFeedbacks(params), + }); +}; diff --git a/src/lib/api/endpoints.ts b/src/lib/api/endpoints.ts index d168ab6..587cb86 100644 --- a/src/lib/api/endpoints.ts +++ b/src/lib/api/endpoints.ts @@ -45,4 +45,9 @@ export const API_ENDPOINTS = { ASSIGN_COMPANY_TO_CUSTOMER: (id: string) => `customers/${id}/companies/assign`, }, + FEEDBACK: { + READ_ALL: "feedback", + DETAILS: (id: string) => `feedback/${id}`, + DELETE: (id: string) => `feedback/${id}`, + }, } as const; diff --git a/src/lib/api/services/feedback-service.ts b/src/lib/api/services/feedback-service.ts new file mode 100644 index 0000000..8319194 --- /dev/null +++ b/src/lib/api/services/feedback-service.ts @@ -0,0 +1,30 @@ +import api from "../axios"; +import { API_ENDPOINTS } from "../endpoints"; +import { ApiResponse } from "../types"; +import { TFeedbackResponse } from "../types/Feedback"; + +export const feedbackService = { + getFeedbacks: async ( + params: Record, + ): Promise => { + try { + return (await api.get(API_ENDPOINTS.FEEDBACK.READ_ALL, { params })).data; + } catch (error) { + console.error("ERROR Caught in feedback service => getFeedbacks", error); + throw error; + } + }, + getSingleFeedback: async ( + id: string, + ): Promise> => { + try { + return (await api.get(API_ENDPOINTS.FEEDBACK.DETAILS(id))).data; + } catch (error) { + console.error( + "ERROR Caught in feedback service => getSingleFeedback", + error, + ); + throw error; + } + }, +}; diff --git a/src/lib/api/types/Feedback.ts b/src/lib/api/types/Feedback.ts new file mode 100644 index 0000000..3d0ef34 --- /dev/null +++ b/src/lib/api/types/Feedback.ts @@ -0,0 +1,16 @@ +import { z } from "zod"; +import { TenderSchema } from "./Tenders"; +export const feedbackSchema = z.object({ + company_id: z.string(), + created_at: z.number(), + customer_id: z.string(), + feedback_type: z.string(), + id: z.string(), + tender: TenderSchema.or(z.null()), + updated_at: z.number(), +}); +export const feedbackResponseSchema = z.object({ + data: z.array(feedbackSchema), +}); +export type TFeedback = z.infer; +export type TFeedbackResponse = z.infer; diff --git a/src/lib/api/types/TCompany.ts b/src/lib/api/types/TCompany.ts index b171b3d..8e5a9e0 100644 --- a/src/lib/api/types/TCompany.ts +++ b/src/lib/api/types/TCompany.ts @@ -52,7 +52,7 @@ export interface ICreateCompanyCredentials { export const companySchema = z.object({ id: z.string(), name: z.string(), - email: z.string().email().optional(), + email: z.string().optional(), phone: z.string().optional(), website: z.string(), type: z.string(), diff --git a/src/lib/api/types/Tenders.ts b/src/lib/api/types/Tenders.ts index 3ffb21c..4d38f4d 100644 --- a/src/lib/api/types/Tenders.ts +++ b/src/lib/api/types/Tenders.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -const TenderSchema = z.object({ +export const TenderSchema = z.object({ id: z.string(), buyer_organization: z.object({ name: z.string(),