Initial commit
This commit is contained in:
31
src/redux/api/apiSlice.ts
Normal file
31
src/redux/api/apiSlice.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import {
|
||||
BaseQueryFn,
|
||||
createApi,
|
||||
FetchArgs,
|
||||
} from "@reduxjs/toolkit/query/react";
|
||||
import { API_BASE_URL } from "utils/constants";
|
||||
import baseQuery from "./baseQuery";
|
||||
|
||||
export type ProServerError = {
|
||||
data: {
|
||||
error: string;
|
||||
description: string;
|
||||
status: "error";
|
||||
};
|
||||
};
|
||||
export const baseApi = createApi({
|
||||
reducerPath: "baseApi",
|
||||
baseQuery: baseQuery({
|
||||
baseUrl: API_BASE_URL,
|
||||
}) as BaseQueryFn<string | FetchArgs, unknown, ProServerError, {}>,
|
||||
tagTypes: [
|
||||
"Orders",
|
||||
"Order",
|
||||
"Menu",
|
||||
"Restaurant",
|
||||
],
|
||||
keepUnusedDataFor: 240, // Keep data for 60 seconds after component unmounts
|
||||
endpoints: () => ({}),
|
||||
});
|
||||
|
||||
export const dummy = [];
|
||||
34
src/redux/api/auth.ts
Normal file
34
src/redux/api/auth.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { CONFIRM_OTP_URL, LOGIN_URL, SEND_OTP_URL } from "utils/constants";
|
||||
import { LoginUserType } from "utils/types/appTypes";
|
||||
import { baseApi } from "./apiSlice";
|
||||
|
||||
export const loginApi = baseApi.injectEndpoints({
|
||||
endpoints: (builder) => ({
|
||||
createLogin: builder.mutation({
|
||||
query: (body: LoginUserType) => ({
|
||||
url: LOGIN_URL,
|
||||
method: "POST",
|
||||
body,
|
||||
}),
|
||||
}),
|
||||
sendOtp: builder.mutation({
|
||||
query: (body: any) => ({
|
||||
url: SEND_OTP_URL,
|
||||
method: "POST",
|
||||
body,
|
||||
}),
|
||||
}),
|
||||
confirmOtp: builder.mutation({
|
||||
query: (body: any) => ({
|
||||
url: CONFIRM_OTP_URL,
|
||||
method: "POST",
|
||||
body,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
export const {
|
||||
useCreateLoginMutation,
|
||||
useSendOtpMutation,
|
||||
useConfirmOtpMutation,
|
||||
} = loginApi;
|
||||
27
src/redux/api/baseQuery.ts
Normal file
27
src/redux/api/baseQuery.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import { fetchBaseQuery, retry } from "@reduxjs/toolkit/query/react";
|
||||
import { getDefaultLanguage } from "i18n/helper";
|
||||
import { ACCESS_TOKEN } from "utils/constants";
|
||||
|
||||
const baseQuery = ({ baseUrl }: { baseUrl: string }) =>
|
||||
retry(
|
||||
fetchBaseQuery({
|
||||
baseUrl,
|
||||
validateStatus: (response, result) => {
|
||||
return response.status?.toString()[0] === "2" && !result.error;
|
||||
},
|
||||
prepareHeaders: (headers) => {
|
||||
const token = localStorage.getItem(ACCESS_TOKEN);
|
||||
|
||||
headers.set("Accept", "application/json");
|
||||
headers.set("Accept-Language", getDefaultLanguage());
|
||||
|
||||
if (token) headers.set("authorization", `Bearer ${token}`);
|
||||
|
||||
return headers;
|
||||
},
|
||||
}),
|
||||
{
|
||||
maxRetries: 0, // Set the maximum number of retries to 3
|
||||
}
|
||||
);
|
||||
export default baseQuery;
|
||||
53
src/redux/api/others.ts
Normal file
53
src/redux/api/others.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import {
|
||||
CREATE_ORDER_URL,
|
||||
ORDERS_URL,
|
||||
PRODUCTS_AND_CATEGORIES_URL,
|
||||
RESTAURANT_DETAILS_URL,
|
||||
} from "utils/constants";
|
||||
|
||||
import menuParser from "pages/menu/helper";
|
||||
import { RestaurantDetails } from "utils/types/appTypes";
|
||||
import { baseApi } from "./apiSlice";
|
||||
|
||||
export const branchApi = baseApi.injectEndpoints({
|
||||
endpoints: (builder) => ({
|
||||
getRestaurantDetails: builder.query<RestaurantDetails, string | void>({
|
||||
query: (restaurantId: string) =>
|
||||
`${RESTAURANT_DETAILS_URL}${restaurantId}`,
|
||||
transformResponse: (response: any) => {
|
||||
return response.result;
|
||||
},
|
||||
}),
|
||||
getMenu: builder.query<any, string | void>({
|
||||
query: (restaurantId: string) =>
|
||||
`${PRODUCTS_AND_CATEGORIES_URL}${restaurantId}`,
|
||||
transformResponse: (response: any) => {
|
||||
return menuParser(response);
|
||||
},
|
||||
}),
|
||||
getOrders: builder.query<any, void>({
|
||||
query: () => ({
|
||||
url: ORDERS_URL,
|
||||
method: "POST",
|
||||
}),
|
||||
transformResponse: (response: any) => {
|
||||
return response.result.data.orders;
|
||||
},
|
||||
providesTags: ["Orders"],
|
||||
}),
|
||||
createOrder: builder.mutation({
|
||||
query: (body: any) => ({
|
||||
url: CREATE_ORDER_URL,
|
||||
method: "POST",
|
||||
body,
|
||||
}),
|
||||
invalidatesTags: ["Orders"],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
export const {
|
||||
useGetRestaurantDetailsQuery,
|
||||
useGetMenuQuery,
|
||||
useCreateOrderMutation,
|
||||
useGetOrdersQuery,
|
||||
} = branchApi;
|
||||
32
src/redux/api/roles.ts
Normal file
32
src/redux/api/roles.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import {
|
||||
PERMISSIONS_DATA_URL,
|
||||
ROLES_DATA_URL,
|
||||
SINGED_USER_INFO_URL
|
||||
} from "utils/constants";
|
||||
import { RolesType, UserType } from "utils/types/appTypes";
|
||||
import { baseApi } from "./apiSlice";
|
||||
|
||||
export const roleApi = baseApi.injectEndpoints({
|
||||
endpoints: (builder) => ({
|
||||
getRoles: builder.query<Array<RolesType>, void>({
|
||||
query: () => ROLES_DATA_URL,
|
||||
transformResponse: (response: any) => {
|
||||
return response.data;
|
||||
},
|
||||
}),
|
||||
getPermissions: builder.query<Array<any>, void>({
|
||||
query: () => PERMISSIONS_DATA_URL,
|
||||
transformResponse: (response: any) => {
|
||||
return response.data;
|
||||
},
|
||||
}),
|
||||
getSignedUserInfo: builder.query<UserType, void>({
|
||||
query: () => SINGED_USER_INFO_URL,
|
||||
}),
|
||||
}),
|
||||
});
|
||||
export const {
|
||||
useGetRolesQuery,
|
||||
useGetPermissionsQuery,
|
||||
useGetSignedUserInfoQuery,
|
||||
} = roleApi;
|
||||
65
src/redux/hooks.ts
Normal file
65
src/redux/hooks.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
import type { TypedUseSelectorHook } from "react-redux";
|
||||
|
||||
import { ItemType, OrderType } from "pages/pos/orders/types";
|
||||
import { TableType } from "pages/pos/tables/types";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { parseTranslations } from "utils/helpers";
|
||||
import type { AppDispatch, RootState } from "./store";
|
||||
|
||||
// Use throughout your app instead of plain `useDispatch` and `useSelector`
|
||||
export const useAppDispatch: () => AppDispatch = useDispatch;
|
||||
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
|
||||
|
||||
export const useDebouncedValue = (value: any, delay: number = 500) => {
|
||||
const [debouncedValue, setDebouncedValue] = useState(value);
|
||||
|
||||
useEffect(() => {
|
||||
const handler: NodeJS.Timeout = setTimeout(() => {
|
||||
setDebouncedValue(value);
|
||||
}, delay);
|
||||
|
||||
return () => {
|
||||
clearTimeout(handler);
|
||||
};
|
||||
}, [value, delay]);
|
||||
|
||||
return debouncedValue;
|
||||
};
|
||||
|
||||
export const useExtractTableItems = (table?: TableType) => {
|
||||
return useMemo(() => {
|
||||
let items: Array<ItemType> = [];
|
||||
let quantity: number = 0;
|
||||
table?.active_reservation?.orders?.forEach((order: OrderType) => {
|
||||
items = [...items, ...(order?.items || [])];
|
||||
quantity += Number(order?.quantities) || 0;
|
||||
});
|
||||
|
||||
items = items.filter((i) => i.quantity > 0);
|
||||
items = [...removeDuplicatesAndIncreaseQuantity(items)];
|
||||
items = items.map((i: any) => ({ ...i, ...parseTranslations(i.product) }));
|
||||
return { items, quantity };
|
||||
}, [table]);
|
||||
};
|
||||
|
||||
export function removeDuplicatesAndIncreaseQuantity(items: any[]) {
|
||||
const result: any[] = [];
|
||||
|
||||
// Group objects by ID
|
||||
const grouped = items.reduce((acc, item) => {
|
||||
if (!acc[item.product.id]) {
|
||||
acc[item.product.id] = { ...item };
|
||||
} else {
|
||||
acc[item.product.id].quantity += item.quantity;
|
||||
acc[item.product.id].total_amount =
|
||||
acc[item.product.id]?.quantity * acc[item.product.id]?.unit_price;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
// Convert grouped objects back to array
|
||||
Object.values(grouped).forEach((item) => result.push(item));
|
||||
return result;
|
||||
}
|
||||
33
src/redux/store.ts
Normal file
33
src/redux/store.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Action, configureStore, ThunkAction } from "@reduxjs/toolkit";
|
||||
import authReducer from "features/auth/authSlice";
|
||||
import appErrorReducer from "features/error/appErrorSlice";
|
||||
import localeReducer from "features/locale/localeSlice";
|
||||
import orderSlice from "features/order/orderSlice";
|
||||
import themeReducer from "features/theme/themeSlice";
|
||||
import { baseApi } from "./api/apiSlice";
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
auth: authReducer,
|
||||
theme: themeReducer,
|
||||
locale: localeReducer,
|
||||
appError: appErrorReducer,
|
||||
order: orderSlice,
|
||||
[baseApi.reducerPath]: baseApi.reducer,
|
||||
},
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware({ serializableCheck: false }).concat(
|
||||
baseApi.middleware
|
||||
),
|
||||
});
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
|
||||
export type AppThunk<ReturnType = void> = ThunkAction<
|
||||
ReturnType,
|
||||
RootState,
|
||||
unknown,
|
||||
Action<string>
|
||||
>;
|
||||
Reference in New Issue
Block a user