diff --git a/src/pages/MyBugs/MyBugsFilters.tsx b/src/pages/MyBugs/MyBugsFilters.tsx deleted file mode 100644 index c4f6db773..000000000 --- a/src/pages/MyBugs/MyBugsFilters.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import { - Select, - SelectType, - SortTableSelect, - SortTableSelectProps, -} from "@appquality/appquality-design-system"; -import { useTranslation } from "react-i18next"; -import { - setSelectedCampaign, - setSelectedSeverity, - setSelectedStatus, -} from "../../redux/myBugs/actionCreator"; -import { useAppDispatch } from "../../redux/provider"; - -interface MyBugsFiltersProps extends SortTableSelectProps { - campaigns: SelectType.Option[]; - severities: SelectType.Option[]; - status: SelectType.Option[]; - selectedCampaign?: SelectType.Option; - selectedSeverity?: SelectType.Option; - selectedStatus?: SelectType.Option; -} - -const MyBugsFilters = ({ - campaigns, - severities, - status, - selectedCampaign, - selectedSeverity, - selectedStatus, - order, - orderBy, - columns, -}: MyBugsFiltersProps) => { - const { t } = useTranslation(); - const dispatch = useAppDispatch(); - const allCampaign = t("All", { context: "female" }); - const allSeverity = t("All", { context: "female" }); - const allStatus = t("All", { context: "male" }); - let campaignValue = { label: allCampaign }; - let severityValue = { label: allSeverity }; - let statusValue = { label: allStatus }; - - if ( - selectedCampaign && - campaigns.map((c) => c.value).includes(selectedCampaign.value) - ) { - campaignValue = selectedCampaign; - } - if ( - selectedSeverity && - severities.map((s) => s.value).includes(selectedSeverity.value) - ) { - severityValue = selectedSeverity; - } - if ( - selectedStatus && - status.map((s) => s.value).includes(selectedStatus.value) - ) { - statusValue = selectedStatus; - } - - return ( -
-
- dispatch(setSelectedSeverity(value))} - name="severity" - options={[{ label: allSeverity }, ...severities]} - value={severityValue} - isSearchable={false} - placeholder={t("Search")} - isClearable={false} - noOptionsMessage={() => t("__SELECT_DEFAULT_NO_OPTION")} - /> -
-
- { + setPage(1); + dispatch(setSelectedCampaign(value)); + }} + name="campaign" + options={campaigns} + value={campaigns.find((c) => c.selected) || campaigns[0]} + isSearchable + placeholder={t("Search")} + isClearable={false} + noOptionsMessage={() => t("__SELECT_DEFAULT_NO_OPTION")} + /> +
+
+ { + setPage(1); + dispatch(setSelectedStatus(value)); + }} + name="status" + options={status} + value={status.find((c) => c.selected) || status[0]} + isSearchable={false} + placeholder={t("Search")} + isClearable={false} + noOptionsMessage={() => t("__SELECT_DEFAULT_NO_OPTION")} + /> +
+ +
+ ); +}; + +export default MyBugsFilters; diff --git a/src/pages/MyBugs/MyBugsFilters/useSelectValues.tsx b/src/pages/MyBugs/MyBugsFilters/useSelectValues.tsx new file mode 100644 index 000000000..c50c6a08d --- /dev/null +++ b/src/pages/MyBugs/MyBugsFilters/useSelectValues.tsx @@ -0,0 +1,94 @@ +import { SelectType } from "@appquality/appquality-design-system"; +import { useTranslation } from "react-i18next"; +import { shallowEqual, useSelector } from "react-redux"; +import { useGetUsersMeBugsQuery } from "src/services/tryberApi"; + +const useSelectValues = () => { + const { t } = useTranslation(); + + const allCampaign = t("All", { context: "female" }); + const allSeverity = t("All", { context: "female" }); + const allStatus = t("All", { context: "male" }); + const { selectedCampaign, selectedSeverity, selectedStatus } = useSelector( + (state: GeneralState) => ({ + selectedCampaign: state.myBugs.selectedCampaign, + selectedSeverity: state.myBugs.selectedSeverity, + selectedStatus: state.myBugs.selectedStatus, + }), + shallowEqual + ); + + const { data, isLoading } = useGetUsersMeBugsQuery({ + filterBy: { + campaign: selectedCampaign?.value, + severity: selectedSeverity?.value, + status: selectedStatus?.value, + }, + }); + + if (isLoading || !data) return { campaigns: [], severities: [], status: [] }; + + const campaigns: SelectType.Option[] = data.results + .filter( + (r): r is { id: number; campaign: { id: number; name: string } } => + typeof r.campaign !== "undefined" + ) + .map((r) => { + return { + value: r.campaign.id.toString(), + selected: selectedCampaign?.value === r.campaign.id.toString(), + label: `CP${r.campaign.id} - ${r.campaign.name}`, + }; + }) + .filter( + (value, index, self) => + index === self.findIndex((t) => t.value === value.value) + ) + .sort((a, b) => { + return Number(b.value) - Number(a.value); + }); + + const severities: SelectType.Option[] = data.results + .filter( + (r): r is { id: number; severity: { id: number; name: string } } => + typeof r.severity !== "undefined" + ) + .map((r) => { + return { + value: r.severity.id.toString(), + selected: selectedSeverity?.value === r.severity.id.toString(), + label: r.severity.name, + }; + }) + .filter( + (value, index, self) => + index === self.findIndex((t) => t.value === value.value) + ) + .sort((a, b) => { + return Number(a.value) - Number(b.value); + }); + + const status: SelectType.Option[] = data.results + .filter( + (r): r is { id: number; status: { id: number; name: string } } => + typeof r.status !== "undefined" + ) + .map((r) => { + return { + value: r.status.id.toString(), + selected: selectedStatus?.value === r.status.id.toString(), + label: r.status.name, + }; + }) + .filter( + (value, index, self) => + index === self.findIndex((t) => t.value === value.value) + ); + return { + campaigns: [{ label: allCampaign }, ...campaigns], + severities: [{ label: allSeverity }, ...severities], + status: [{ label: allStatus }, ...status], + }; +}; + +export { useSelectValues }; diff --git a/src/pages/MyBugs/MyBugsTable.tsx b/src/pages/MyBugs/MyBugsTable.tsx index a3b1cfd86..0695e6716 100644 --- a/src/pages/MyBugs/MyBugsTable.tsx +++ b/src/pages/MyBugs/MyBugsTable.tsx @@ -1,40 +1,96 @@ import { - Table, + Button, Pagination, - TableType, + Table, } from "@appquality/appquality-design-system"; import { useTranslation } from "react-i18next"; +import { shallowEqual, useSelector } from "react-redux"; +import i18n from "src/i18n"; +import { coloredStatus } from "src/redux/myBugs/utils"; +import { useGetUsersMeBugsQuery } from "src/services/tryberApi"; +import { useBugColumns } from "./columns"; +import { usePage } from "./usePage"; -interface MyBugsTableProps { - data: TableType.Row[]; - page: number; - setPage: (page: number) => void; - totalBugs: number; - limit: number; - loading: boolean; - columns: TableType.Column[]; - order: ApiComponents["parameters"]["order"]; - orderBy: string; -} - -const MyBugsTable = ({ - data, - page, - setPage, - totalBugs, - limit, - order, - orderBy, - loading, - columns, -}: MyBugsTableProps) => { +const MyBugsTable = () => { const { t } = useTranslation(); + const { page, setPage } = usePage(); + const columns = useBugColumns(); + const { selectedCampaign, selectedSeverity, selectedStatus } = useSelector( + (state: GeneralState) => ({ + selectedCampaign: state.myBugs.selectedCampaign, + selectedSeverity: state.myBugs.selectedSeverity, + selectedStatus: state.myBugs.selectedStatus, + }), + shallowEqual + ); + const { limit, start, order, orderBy } = useSelector( + (state: GeneralState) => ({ + limit: state.myBugs.bugsList.limit, + start: state.myBugs.bugsList.start, + order: state.myBugs.bugsList.order, + orderBy: state.myBugs.bugsList.orderBy, + }), + shallowEqual + ); + + const { data, isLoading: loading } = useGetUsersMeBugsQuery({ + start: start, + limit: limit, + orderBy: orderBy, + order: order, + filterBy: { + campaign: selectedCampaign?.value, + severity: selectedSeverity?.value, + status: selectedStatus?.value, + }, + }); + const { results, total } = data || {}; + + const totalBugs = total ?? 0; + + const rows = (results || []).map((res) => { + let status = res.status + ? { + title: res.status.name, + content: ( + + {res.status.name} + + ), + } + : "unknown"; + return { + key: res.id, + id: res.id, + severity: res.severity?.name, + status: status, + title: res.title?.replace(/\\(.)/gm, "$1"), + action: { + title: `${window.location.origin}/${ + i18n.language !== "en" ? `${i18n.language}/` : "" + }bugs/show/${res.id}`, + content: ( + + ), + }, + }; + }); return ( <> -): Column[] => { +export const useBugColumns = (): Column[] => { + const { t } = useTranslation(); + const dispatch = useAppDispatch(); return [ { title: "Id", diff --git a/src/pages/MyBugs/index.tsx b/src/pages/MyBugs/index.tsx index 5e51f056c..f5e2d221b 100644 --- a/src/pages/MyBugs/index.tsx +++ b/src/pages/MyBugs/index.tsx @@ -1,142 +1,20 @@ -import { - BSCol, - BSGrid, - Button, - Card, - TableType, -} from "@appquality/appquality-design-system"; -import queryString from "query-string"; -import { useEffect, useState } from "react"; +import { BSCol, BSGrid, Card } from "@appquality/appquality-design-system"; import { useTranslation } from "react-i18next"; -import { shallowEqual, useSelector } from "react-redux"; -import { useLocation } from "react-router-dom"; import { PageTemplate } from "src/features/PageTemplate"; -import { useGetUsersMeBugsQuery } from "src/services/tryberApi"; -import i18n from "../../i18n"; -import { - fetchMyBugs, - fetchMyBugsFilters, - setSelectedCampaign, - setSelectedStatus, - updateMybugsPagination, -} from "../../redux/myBugs/actionCreator"; -import { coloredStatus } from "../../redux/myBugs/utils"; -import { useAppDispatch } from "../../redux/provider"; import MyBugsFilters from "./MyBugsFilters"; import MyBugsTable from "./MyBugsTable"; -import { MyBugsColumns } from "./columns"; +import { useQueryStringFilters } from "./useQueryStringFilters"; export default function MyBugs() { - const { search } = useLocation(); const { t } = useTranslation(); - const dispatch = useAppDispatch(); - const [columns, setcolumns] = useState( - MyBugsColumns(dispatch, t) - ); - const [rows, setRows] = useState([]); - - const { - bugsList, - campaigns, - severities, - status, - selectedCampaign, - selectedSeverity, - selectedStatus, - // isLoading, - } = useSelector((state: GeneralState) => state.myBugs, shallowEqual); - - const { isLoading, data } = useGetUsersMeBugsQuery({}); - - const { results, limit, total, start, order, orderBy } = bugsList; - - const changePagination = (newPage: number) => { - const newStart = limit * (newPage - 1); - dispatch(updateMybugsPagination(newStart)); - }; - - useEffect(() => { - const values = queryString.parse(search); - if (values.cp) { - dispatch(setSelectedCampaign({ value: values.cp.toString(), label: "" })); - } - if (values.status) { - dispatch( - setSelectedStatus({ value: values.status.toString(), label: "" }) - ); - } - }, [queryString]); - - useEffect(() => { - setRows( - results.map((res) => { - let status = res.status - ? { - title: res.status.name, - content: ( - - {res.status.name} - - ), - } - : "unknown"; - return { - key: res.id, - id: res.id, - severity: res.severity?.name, - status: status, - title: res.title?.replace(/\\(.)/gm, "$1"), - action: { - title: `${window.location.origin}/${ - i18n.language !== "en" ? `${i18n.language}/` : "" - }bugs/show/${res.id}`, - content: ( - - ), - }, - }; - }) - ); - }, [results]); - - useEffect(() => { - if (selectedCampaign || selectedSeverity || selectedStatus) { - changePagination(1); - dispatch(fetchMyBugsFilters()); - } - }, [selectedCampaign, selectedSeverity, selectedStatus]); - - useEffect(() => { - dispatch(fetchMyBugs()); - dispatch(fetchMyBugsFilters()); - }, []); + useQueryStringFilters(); return ( - + @@ -145,17 +23,7 @@ export default function MyBugs() { title={t("Filters")} shadow={true} > - + diff --git a/src/pages/MyBugs/usePage.tsx b/src/pages/MyBugs/usePage.tsx new file mode 100644 index 000000000..6e1f53083 --- /dev/null +++ b/src/pages/MyBugs/usePage.tsx @@ -0,0 +1,29 @@ +import { shallowEqual, useSelector } from "react-redux"; +import { updateMybugsPagination } from "src/redux/myBugs/actionCreator"; +import { useAppDispatch } from "src/store"; + +const usePage = () => { + const dispatch = useAppDispatch(); + + const { limit, start } = useSelector( + (state: GeneralState) => ({ + limit: state.myBugs.bugsList.limit, + start: state.myBugs.bugsList.start, + order: state.myBugs.bugsList.order, + orderBy: state.myBugs.bugsList.orderBy, + }), + shallowEqual + ); + + const changePagination = (newPage: number) => { + const newStart = limit * (newPage - 1); + dispatch(updateMybugsPagination(newStart)); + }; + + return { + page: (start || 0) / limit + 1, + setPage: changePagination, + }; +}; + +export { usePage }; diff --git a/src/pages/MyBugs/useQueryStringFilters.tsx b/src/pages/MyBugs/useQueryStringFilters.tsx new file mode 100644 index 000000000..c7b4740ff --- /dev/null +++ b/src/pages/MyBugs/useQueryStringFilters.tsx @@ -0,0 +1,27 @@ +import queryString from "query-string"; +import { useEffect } from "react"; +import { useLocation } from "react-router-dom"; +import { useAppDispatch } from "src/store"; +import { + setSelectedCampaign, + setSelectedStatus, +} from "../../redux/myBugs/actionCreator"; + +const useQueryStringFilters = () => { + const dispatch = useAppDispatch(); + const { search } = useLocation(); + + useEffect(() => { + const values = queryString.parse(search); + if (values.cp) { + dispatch(setSelectedCampaign({ value: values.cp.toString(), label: "" })); + } + if (values.status) { + dispatch( + setSelectedStatus({ value: values.status.toString(), label: "" }) + ); + } + }, [queryString]); +}; + +export { useQueryStringFilters };