diff --git a/src/pages/ExperiencePoints/ExperiencePointsFilters.tsx b/src/pages/ExperiencePoints/ExperiencePointsFilters/index.tsx
similarity index 50%
rename from src/pages/ExperiencePoints/ExperiencePointsFilters.tsx
rename to src/pages/ExperiencePoints/ExperiencePointsFilters/index.tsx
index b7b5f35a4..70587ffb0 100644
--- a/src/pages/ExperiencePoints/ExperiencePointsFilters.tsx
+++ b/src/pages/ExperiencePoints/ExperiencePointsFilters/index.tsx
@@ -6,38 +6,121 @@ import {
} from "@appquality/appquality-design-system";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
+import { shallowEqual, useSelector } from "react-redux";
import useDebounce from "src/hooks/useDebounce";
import {
setSelectedActivity,
setSelectedCampaign,
setSelectedDate,
-} from "../../redux/experiencePoints/actionCreator";
-import { useAppDispatch } from "../../redux/provider";
+} from "src/redux/experiencePoints/actionCreator";
+import { mapActivityName } from "src/redux/experiencePoints/utils";
+import { useAppDispatch } from "src/redux/provider";
+import { useGetUsersMeExperienceQuery } from "src/services/tryberApi";
+import dateFormatter from "src/utils/dateFormatter";
-interface ExperiencePointsFiltersProps {
- campaigns: SelectType.Option[];
- activities: SelectType.Option[];
- dates: SelectType.Option[];
- selectedCampaign?: SelectType.Option;
- selectedActivity?: SelectType.Option;
- selectedDate?: SelectType.Option;
- search?: string;
-}
+const useSelectValues = () => {
+ const { t } = useTranslation();
+
+ const { selectedActivity, selectedCampaign, selectedDate, search } =
+ useSelector((state: GeneralState) => state.experiencePoints, shallowEqual);
+
+ const { data, isLoading } = useGetUsersMeExperienceQuery({
+ searchBy: "note",
+ search: search,
+ filterBy: {
+ campaign: selectedCampaign?.value,
+ activity: selectedActivity?.value,
+ date: selectedDate?.value,
+ },
+ });
+ if (isLoading || !data) return { campaigns: [], activities: [], dates: [] };
+
+ const campaigns: SelectType.Option[] = data.results
+ .filter(
+ (
+ r
+ ): r is {
+ id: number;
+ activity: { id: number };
+ campaign: { id: number; title?: string | undefined };
+ date: string;
+ amount: number;
+ note?: string | undefined;
+ } => typeof r.campaign.title !== "undefined"
+ )
+ .map((r) => {
+ return {
+ value: r.campaign.id.toString(),
+ label: `CP${r.campaign.id} - ${r.campaign.title}`,
+ };
+ })
+ .filter(
+ (value, index, self) =>
+ index === self.findIndex((t) => t.value === value.value)
+ );
+
+ const activities: SelectType.Option[] = data.results
+ .filter(
+ (
+ r
+ ): r is {
+ id: number;
+ activity: { id: number };
+ campaign: { id: number; title?: string | undefined };
+ date: string;
+ amount: number;
+ note?: string | undefined;
+ } => typeof r.activity !== "undefined"
+ )
+ .map((r) => {
+ return {
+ value: r.activity.id.toString(),
+ label: mapActivityName(r.activity.id, t) || " ",
+ };
+ })
+ .filter(
+ (value, index, self) =>
+ index === self.findIndex((t) => t.value === value.value)
+ );
-const ExperiencePointsFilters = ({
- search,
- campaigns,
- dates,
- activities,
- selectedCampaign,
- selectedActivity,
- selectedDate,
-}: ExperiencePointsFiltersProps) => {
+ const dates: SelectType.Option[] = data.results
+ .filter(
+ (
+ r
+ ): r is {
+ id: number;
+ activity: { id: number };
+ campaign: { id: number; title?: string | undefined };
+ date: string;
+ amount: number;
+ note?: string | undefined;
+ } => typeof r.date !== "undefined"
+ )
+ .map((r) => {
+ return {
+ value: r.date,
+ label: dateFormatter(r.date),
+ };
+ })
+ .filter(
+ (value, index, self) =>
+ index === self.findIndex((t) => t.value === value.value)
+ );
+
+ return { campaigns, activities, dates };
+};
+
+const ExperiencePointsFilters = () => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
+
+ const { selectedActivity, selectedCampaign, selectedDate, search } =
+ useSelector((state: GeneralState) => state.experiencePoints, shallowEqual);
const [currentSearch, setCurrentSearch] = useState(search);
const debouncedSearch = useDebounce(currentSearch, 500);
+ const { campaigns, activities, dates } = useSelectValues();
+
const allCampaign = t("All", { context: "female" });
const allActivities = t("All", { context: "female" });
const allDates = t("All", { context: "female" });
diff --git a/src/pages/ExperiencePoints/ExperiencePointsTable.tsx b/src/pages/ExperiencePoints/ExperiencePointsTable.tsx
deleted file mode 100644
index fe21e680a..000000000
--- a/src/pages/ExperiencePoints/ExperiencePointsTable.tsx
+++ /dev/null
@@ -1,65 +0,0 @@
-import {
- Table,
- Pagination,
- TableType,
- SortTableSelect,
-} from "@appquality/appquality-design-system";
-import { useTranslation } from "react-i18next";
-
-interface ExperiencePointsTableProps {
- data: TableType.Row[];
- page: number;
- setPage: (page: number) => void;
- totalEntries: number;
- limit: number;
- loading: boolean;
- columns: TableType.Column[];
- order: ApiComponents["parameters"]["order"];
- orderBy: string;
-}
-
-const ExperiencePointsTable = ({
- data,
- page,
- setPage,
- totalEntries,
- limit,
- loading,
- order,
- orderBy,
- columns,
-}: ExperiencePointsTableProps) => {
- const { t } = useTranslation();
-
- return (
- <>
-
-
-
- t(`Page %current% / %total%`)
- .replace("%current%", current.toString())
- .replace("%total%", total ? total.toString() : "0")
- }
- />
- >
- );
-};
-
-export default ExperiencePointsTable;
diff --git a/src/pages/ExperiencePoints/ExperiencePointsTable/index.tsx b/src/pages/ExperiencePoints/ExperiencePointsTable/index.tsx
new file mode 100644
index 000000000..75d258ab9
--- /dev/null
+++ b/src/pages/ExperiencePoints/ExperiencePointsTable/index.tsx
@@ -0,0 +1,66 @@
+import {
+ Pagination,
+ SortTableSelect,
+ Table,
+} from "@appquality/appquality-design-system";
+import { useTranslation } from "react-i18next";
+import { shallowEqual, useSelector } from "react-redux";
+import { updateExperiencePointsPagination } from "src/redux/experiencePoints/actionCreator";
+import { useAppDispatch } from "src/store";
+import { useExperiencePointsColumns } from "../columns";
+import { useResetPaginationOnFilterChange } from "./useResetPaginationOnFilterChange";
+import { useRows } from "./useRows";
+
+const ExperiencePointsTable = () => {
+ const limit = 25;
+ const { t } = useTranslation();
+ const dispatch = useAppDispatch();
+ const { rows, loading, totalEntries } = useRows();
+ const columns = useExperiencePointsColumns();
+
+ const setPage = (newPage: number) => {
+ const newStart = limit * (newPage - 1);
+ dispatch(updateExperiencePointsPagination(newStart));
+ };
+
+ useResetPaginationOnFilterChange({ setPage });
+
+ const { order, orderBy, start } = useSelector(
+ (state: GeneralState) => state.experiencePoints.expList,
+ shallowEqual
+ );
+
+ const page = (start ?? 0) / limit + 1;
+
+ return (
+ <>
+
+
+
+ t(`Page %current% / %total%`)
+ .replace("%current%", current.toString())
+ .replace("%total%", total ? total.toString() : "0")
+ }
+ />
+ >
+ );
+};
+
+export default ExperiencePointsTable;
diff --git a/src/pages/ExperiencePoints/ExperiencePointsTable/useResetPaginationOnFilterChange.tsx b/src/pages/ExperiencePoints/ExperiencePointsTable/useResetPaginationOnFilterChange.tsx
new file mode 100644
index 000000000..b4d584989
--- /dev/null
+++ b/src/pages/ExperiencePoints/ExperiencePointsTable/useResetPaginationOnFilterChange.tsx
@@ -0,0 +1,25 @@
+import { useEffect } from "react";
+import { shallowEqual, useSelector } from "react-redux";
+
+const useResetPaginationOnFilterChange = ({
+ setPage,
+}: {
+ setPage: (newPage: number) => void;
+}) => {
+ const { selectedActivity, selectedCampaign, selectedDate, search } =
+ useSelector((state: GeneralState) => state.experiencePoints, shallowEqual);
+
+ useEffect(() => {
+ if (
+ selectedCampaign ||
+ selectedActivity ||
+ selectedDate ||
+ search ||
+ search === ""
+ ) {
+ setPage(1);
+ }
+ }, [selectedCampaign, selectedActivity, selectedDate, search]);
+};
+
+export { useResetPaginationOnFilterChange };
diff --git a/src/pages/ExperiencePoints/ExperiencePointsTable/useRows.tsx b/src/pages/ExperiencePoints/ExperiencePointsTable/useRows.tsx
new file mode 100644
index 000000000..963208216
--- /dev/null
+++ b/src/pages/ExperiencePoints/ExperiencePointsTable/useRows.tsx
@@ -0,0 +1,77 @@
+import { useTranslation } from "react-i18next";
+import { shallowEqual, useSelector } from "react-redux";
+import { mapActivityName } from "src/redux/experiencePoints/utils";
+import { useGetUsersMeExperienceQuery } from "src/services/tryberApi";
+import dateFormatter from "src/utils/dateFormatter";
+
+const useRows = () => {
+ const limit = 25;
+ const { t } = useTranslation();
+
+ const { order, orderBy, start } = useSelector(
+ (state: GeneralState) => state.experiencePoints.expList,
+ shallowEqual
+ );
+ const { selectedActivity, selectedCampaign, selectedDate, search } =
+ useSelector((state: GeneralState) => state.experiencePoints, shallowEqual);
+
+ const {
+ data,
+ error,
+ isLoading: loading,
+ } = useGetUsersMeExperienceQuery({
+ limit: limit,
+ start: start,
+ order: order,
+ orderBy: orderBy,
+ search: search,
+ searchBy: "note",
+ filterBy: {
+ campaign: selectedCampaign?.value,
+ activity: selectedActivity?.value,
+ date: selectedDate?.value,
+ },
+ });
+
+ if (error) {
+ return {
+ rows: [],
+ loading: false,
+ totalEntries: 0,
+ };
+ }
+
+ const { results, total } = data ?? {};
+
+ const rows = (results ?? []).map((res) => {
+ return {
+ key: res.id,
+ amount: {
+ title: `${res.amount > 0 ? `+${res.amount}` : res.amount}pts`,
+ content:
+ res.amount === 0 ? (
+ {res.amount}pts
+ ) : res.amount > 0 ? (
+ +{res.amount}pts
+ ) : (
+ {res.amount}pts
+ ),
+ },
+ date: dateFormatter(res.date),
+ activity: mapActivityName(res.activity.id, t),
+ campaign:
+ res.campaign.title && res.campaign.id > 0
+ ? `CP${res.campaign.id}`
+ : `-`,
+ note: res.note?.replace(/\\(.)/gm, "$1"),
+ };
+ });
+
+ return {
+ rows,
+ loading,
+ totalEntries: total ?? 0,
+ };
+};
+
+export { useRows };
diff --git a/src/pages/ExperiencePoints/columns.ts b/src/pages/ExperiencePoints/columns.ts
index b571d50f8..382e88237 100644
--- a/src/pages/ExperiencePoints/columns.ts
+++ b/src/pages/ExperiencePoints/columns.ts
@@ -1,11 +1,11 @@
import { Column } from "@appquality/appquality-design-system/dist/stories/table/_types";
-import { TFunction } from "react-i18next";
+import { useTranslation } from "react-i18next";
+import { useAppDispatch } from "src/store";
import { updateExperiencePointsSortingOptions } from "../../redux/experiencePoints/actionCreator";
-export const ExperiencePointsColumns = (
- dispatch: AppDispatch,
- t: TFunction<"translation">
-): Column[] => {
+export const useExperiencePointsColumns = (): Column[] => {
+ const { t } = useTranslation("translation");
+ const dispatch = useAppDispatch();
return [
{
title: t("Points"),
diff --git a/src/pages/ExperiencePoints/index.tsx b/src/pages/ExperiencePoints/index.tsx
index a2e16bc06..c57893201 100644
--- a/src/pages/ExperiencePoints/index.tsx
+++ b/src/pages/ExperiencePoints/index.tsx
@@ -3,101 +3,15 @@ import {
BSGrid,
Button,
Card,
- TableType,
Text,
} from "@appquality/appquality-design-system";
-import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
-import { shallowEqual, useSelector } from "react-redux";
import { PageTemplate } from "src/features/PageTemplate";
-import {
- fetchExperiencePoints,
- fetchExperiencePointsFilters,
- updateExperiencePointsPagination,
-} from "../../redux/experiencePoints/actionCreator";
-import { mapActivityName } from "../../redux/experiencePoints/utils";
-import { useAppDispatch } from "../../redux/provider";
-import dateFormatter from "../../utils/dateFormatter";
-import { ExperiencePointsColumns } from "./columns";
import ExperiencePointsFilters from "./ExperiencePointsFilters";
import ExperiencePointsTable from "./ExperiencePointsTable";
export default function ExperiencePoints() {
const { t } = useTranslation();
- const dispatch = useAppDispatch();
- const [columns, setcolumns] = useState(
- ExperiencePointsColumns(dispatch, t)
- );
- const [rows, setRows] = useState([]);
-
- const {
- expList,
- campaigns,
- activities,
- dates,
- selectedCampaign,
- selectedActivity,
- selectedDate,
- search,
- isLoading,
- } = useSelector(
- (state: GeneralState) => state.experiencePoints,
- shallowEqual
- );
-
- const { results, limit, total, start, order, orderBy } = expList;
-
- const changePagination = (newPage: number) => {
- const newStart = limit * (newPage - 1);
- dispatch(updateExperiencePointsPagination(newStart));
- };
-
- useEffect(() => {
- setRows(
- results.map((res) => {
- return {
- key: res.id,
- amount: {
- title: `${res.amount > 0 ? `+${res.amount}` : res.amount}pts`,
- content:
- res.amount === 0 ? (
- {res.amount}pts
- ) : res.amount > 0 ? (
- +{res.amount}pts
- ) : (
- {res.amount}pts
- ),
- },
- date: dateFormatter(res.date),
- activity: mapActivityName(res.activity.id, t),
- campaign:
- res.campaign.title && res.campaign.id > 0
- ? `CP${res.campaign.id}`
- : `-`,
- note: res.note?.replace(/\\(.)/gm, "$1"),
- };
- })
- );
- }, [results]);
-
- useEffect(() => {
- if (
- selectedCampaign ||
- selectedActivity ||
- selectedDate ||
- search ||
- search === ""
- ) {
- changePagination(1);
- dispatch(fetchExperiencePointsFilters(t));
- }
- }, [selectedCampaign, selectedActivity, selectedDate, search]);
-
- useEffect(() => {
- dispatch(fetchExperiencePoints());
- dispatch(fetchExperiencePointsFilters(t));
- }, []);
-
return (
-
+
-
+
diff --git a/src/redux/experiencePoints/actionCreator.ts b/src/redux/experiencePoints/actionCreator.ts
index 43c4b37a8..ff1b40362 100644
--- a/src/redux/experiencePoints/actionCreator.ts
+++ b/src/redux/experiencePoints/actionCreator.ts
@@ -1,76 +1,5 @@
import { SelectType } from "@appquality/appquality-design-system";
-import { TFunction } from "i18next";
import { ThunkAction } from "redux-thunk";
-import API from "../../utils/api";
-import dateFormatter from "../../utils/dateFormatter";
-import { addMessage } from "../siteWideMessages/actionCreators";
-import { mapActivityName } from "./utils";
-
-export const fetchExperiencePoints =
- (): ThunkAction<
- Promise
,
- GeneralState,
- unknown,
- ExperiencePointsActions
- > =>
- async (dispatch, getState) => {
- const {
- experiencePoints: {
- expList,
- selectedCampaign,
- selectedActivity,
- selectedDate,
- search,
- },
- } = getState();
- dispatch({
- type: "experiencePoints/setIsLoading",
- payload: true,
- });
- try {
- const query: ApiOperations["get-users-me-experience"]["parameters"]["query"] =
- {
- order: expList.order,
- orderBy: expList.orderBy,
- limit: expList.limit,
- start: expList.start,
- filterBy: {
- ...(selectedCampaign?.value && {
- campaign: selectedCampaign.value,
- }),
- ...(selectedActivity?.value && {
- activity: selectedActivity.value,
- }),
- ...(selectedDate?.value && { date: selectedDate.value }),
- },
- search: search,
- searchBy: search && "note",
- };
- const data = await API.experiencePoints({ query });
- dispatch({
- type: "experiencePoints/updateExpList",
- payload: data,
- });
- } catch (e) {
- const error = e as HttpError;
- if (error.statusCode === 404) {
- const { start, limit, size } = expList;
- if ((start || 0) - limit >= 0) {
- dispatch(updateExperiencePointsPagination((start || 0) - limit));
- }
- dispatch({
- type: "experiencePoints/updateExpList",
- payload: {
- size: size,
- start: start,
- results: [],
- },
- });
- } else {
- addMessage(error.message, "danger", false);
- }
- }
- };
export const updateExperiencePointsPagination =
(
@@ -86,7 +15,6 @@ export const updateExperiencePointsPagination =
type: "experiencePoints/updateExpListQuery",
payload: { start: newStart },
});
- return dispatch(fetchExperiencePoints());
};
export const updateExperiencePointsSortingOptions =
@@ -104,107 +32,6 @@ export const updateExperiencePointsSortingOptions =
type: "experiencePoints/updateExpListQuery",
payload: { order: order, orderBy: orderBy },
});
- return dispatch(fetchExperiencePoints());
- };
-
-export const fetchExperiencePointsFilters =
- (
- t: TFunction
- ): ThunkAction<
- Promise,
- GeneralState,
- unknown,
- ExperiencePointsActions
- > =>
- async (dispatch, getState) => {
- const {
- experiencePoints: {
- expList,
- selectedCampaign,
- selectedActivity,
- selectedDate,
- search,
- },
- } = getState();
- dispatch({
- type: "experiencePoints/setIsLoading",
- payload: true,
- });
- try {
- const query: ApiOperations["get-users-me-experience"]["parameters"]["query"] =
- {
- orderBy: "id",
- order: "DESC",
- filterBy: {
- ...(selectedCampaign?.value && {
- campaign: selectedCampaign.value,
- }),
- ...(selectedActivity?.value && {
- activity: selectedActivity.value,
- }),
- ...(selectedDate?.value && { date: selectedDate.value }),
- },
- search: search,
- searchBy: search && "note",
- };
- const data = await API.experiencePoints({ query });
-
- let _campaigns: SelectType.Option[] = [];
- let _activities: SelectType.Option[] = [];
- let _dates: SelectType.Option[] = [];
-
- data.results.forEach((res: any) => {
- if (
- typeof res.campaign === "undefined" ||
- typeof res.activity === "undefined" ||
- typeof res.date === "undefined"
- )
- return;
- if (res.campaign?.id && res.campaign?.title) {
- _campaigns[res.campaign.id] = {
- label: `CP${res.campaign?.id} - ${res.campaign?.title}` || "",
- value: res.campaign.id.toString(),
- };
- }
- if (res.activity?.id) {
- _activities[res.activity.id] = {
- label: mapActivityName(res.activity.id, t) || "",
- value: res.activity.id.toString(),
- };
- }
- if (res.date) {
- let d = new Date(res.date);
- _dates[d.getTime()] = {
- label: dateFormatter(res.date) || "",
- value: res.date,
- };
- }
- });
-
- let datesFilter = Object.values(_dates).filter((el) => el != null);
- if (expList.orderBy === "date" && expList.order === "ASC")
- datesFilter = datesFilter.reverse();
-
- dispatch({
- type: "experiencePoints/setCampaigns",
- payload: _campaigns.filter((el) => el != null).reverse(),
- });
- dispatch({
- type: "experiencePoints/setActivities",
- payload: _activities.filter((el) => el != null),
- });
- dispatch({
- type: "experiencePoints/setDates",
- payload: datesFilter,
- });
- } catch (e) {
- const error = e as HttpError;
- console.log(error);
- }
- dispatch({
- type: "experiencePoints/setIsLoading",
- payload: false,
- });
};
export const setSelectedCampaign =