mirror of
https://github.com/Nezumi-2711/react-training.git
synced 2026-09-22 13:38:51 +00:00
Merge pull request #38 from Nez27/feat/update-hooks-and-services
Update hooks and services
This commit is contained in:
@@ -18,7 +18,11 @@ const useCreateRoom = () => {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { dispatch } = useUserRoomAvailable();
|
const { dispatch } = useUserRoomAvailable();
|
||||||
|
|
||||||
const { mutate: createRoom, isPending: isCreating } = useMutation({
|
const {
|
||||||
|
mutate: createRoom,
|
||||||
|
isPending: isCreating,
|
||||||
|
isSuccess,
|
||||||
|
} = useMutation({
|
||||||
mutationFn: createRoomFn,
|
mutationFn: createRoomFn,
|
||||||
onSuccess: (room) => {
|
onSuccess: (room) => {
|
||||||
toast.success(ADD_SUCCESS);
|
toast.success(ADD_SUCCESS);
|
||||||
@@ -33,7 +37,7 @@ const useCreateRoom = () => {
|
|||||||
onError: (err) => toast.error(err.message),
|
onError: (err) => toast.error(err.message),
|
||||||
});
|
});
|
||||||
|
|
||||||
return { isCreating, createRoom };
|
return { isCreating, createRoom, isSuccess };
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useCreateRoom };
|
export { useCreateRoom };
|
||||||
|
|||||||
@@ -14,7 +14,11 @@ import * as messages from '@constant/messages';
|
|||||||
const useDeleteRoom = () => {
|
const useDeleteRoom = () => {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const { isPending: isDeleting, mutate: deleteRoom } = useMutation({
|
const {
|
||||||
|
isPending: isDeleting,
|
||||||
|
mutate: deleteRoom,
|
||||||
|
isSuccess
|
||||||
|
} = useMutation({
|
||||||
mutationFn: deleteRoomFn,
|
mutationFn: deleteRoomFn,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success(messages.DELETE_SUCCESS);
|
toast.success(messages.DELETE_SUCCESS);
|
||||||
@@ -25,7 +29,7 @@ const useDeleteRoom = () => {
|
|||||||
onError: (err) => toast.error(err.message),
|
onError: (err) => toast.error(err.message),
|
||||||
});
|
});
|
||||||
|
|
||||||
return { isDeleting, deleteRoom };
|
return { isDeleting, deleteRoom, isSuccess };
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useDeleteRoom };
|
export { useDeleteRoom };
|
||||||
|
|||||||
@@ -1,34 +1,79 @@
|
|||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
import { getAllRooms } from '@service/roomServices';
|
import { getAllRooms } from '@service/roomServices';
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { DEFAULT_PAGE_SIZE } from '@constant/config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch room from database
|
* Fetch room from database
|
||||||
* @returns The status of loading rooms from database and data of rooms
|
* @returns The status of loading rooms from database and data of rooms
|
||||||
*/
|
*/
|
||||||
const useRooms = () => {
|
const useRooms = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
|
||||||
const sortByValue = searchParams.get('sortBy') || 'id';
|
const sortByValue = searchParams.get('sortBy') || 'id';
|
||||||
const orderByValue = searchParams.get('orderBy') || 'asc';
|
const orderByValue = searchParams.get('orderBy') || 'asc';
|
||||||
const phoneSearch = searchParams.get('search') || '';
|
const searchValue = searchParams.get('search') || '';
|
||||||
|
const page = searchParams.get('page') ? Number(searchParams.get('page')) : 1;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
data: rooms,
|
data: { data: rooms, count } = {},
|
||||||
error,
|
error,
|
||||||
} = useQuery({
|
} = useQuery({
|
||||||
queryKey: ['rooms', sortByValue, orderByValue, phoneSearch],
|
queryKey: ['rooms', sortByValue, orderByValue, searchValue, page],
|
||||||
queryFn: () => getAllRooms(sortByValue, orderByValue, phoneSearch),
|
queryFn: () =>
|
||||||
|
getAllRooms({
|
||||||
|
sortBy: sortByValue,
|
||||||
|
orderBy: orderByValue,
|
||||||
|
roomName: searchValue,
|
||||||
|
page,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error(error.message);
|
toast.error(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { isLoading, rooms };
|
// Pre-fetching
|
||||||
|
const totalPage = Math.ceil(count! / DEFAULT_PAGE_SIZE);
|
||||||
|
|
||||||
|
if (page < totalPage) {
|
||||||
|
const nextPage = page + 1;
|
||||||
|
|
||||||
|
queryClient.prefetchQuery({
|
||||||
|
queryKey: ['rooms', sortByValue, orderByValue, searchValue, nextPage],
|
||||||
|
queryFn: () =>
|
||||||
|
getAllRooms({
|
||||||
|
sortBy: sortByValue,
|
||||||
|
orderBy: orderByValue,
|
||||||
|
roomName: searchValue,
|
||||||
|
page: nextPage,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page > 1) {
|
||||||
|
const previousPage = page - 1;
|
||||||
|
|
||||||
|
queryClient.prefetchQuery({
|
||||||
|
queryKey: ['rooms', sortByValue, orderByValue, searchValue, previousPage],
|
||||||
|
queryFn: () =>
|
||||||
|
getAllRooms({
|
||||||
|
sortBy: sortByValue,
|
||||||
|
orderBy: orderByValue,
|
||||||
|
roomName: searchValue,
|
||||||
|
page: previousPage,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { isLoading, rooms, count };
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useRooms };
|
export { useRooms };
|
||||||
|
|||||||
@@ -18,14 +18,18 @@ const useUpdateRoom = () => {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { dispatch } = useUserRoomAvailable();
|
const { dispatch } = useUserRoomAvailable();
|
||||||
|
|
||||||
const { mutate: updateRoom, isPending: isUpdating } = useMutation({
|
const {
|
||||||
|
mutate: updateRoom,
|
||||||
|
isPending: isUpdating,
|
||||||
|
isSuccess
|
||||||
|
} = useMutation({
|
||||||
mutationFn: updateRoomFn,
|
mutationFn: updateRoomFn,
|
||||||
onSuccess: (room) => {
|
onSuccess: (room) => {
|
||||||
toast.success(UPDATE_SUCCESS);
|
toast.success(UPDATE_SUCCESS);
|
||||||
queryClient.invalidateQueries({ queryKey: ['rooms'] });
|
queryClient.invalidateQueries({ queryKey: ['rooms'] });
|
||||||
|
|
||||||
// Update name room in global state
|
// Update name room in global state
|
||||||
dispatch!({
|
dispatch?.({
|
||||||
type: 'updateRoomName',
|
type: 'updateRoomName',
|
||||||
payload: [{ id: room.id, name: room.name }],
|
payload: [{ id: room.id, name: room.name }],
|
||||||
});
|
});
|
||||||
@@ -33,7 +37,7 @@ const useUpdateRoom = () => {
|
|||||||
onError: (err) => toast.error(err.message),
|
onError: (err) => toast.error(err.message),
|
||||||
});
|
});
|
||||||
|
|
||||||
return { isUpdating, updateRoom };
|
return { isUpdating, updateRoom, isSuccess };
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useUpdateRoom };
|
export { useUpdateRoom };
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ const useCreateUser = () => {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { dispatch } = useUserRoomAvailable();
|
const { dispatch } = useUserRoomAvailable();
|
||||||
|
|
||||||
const { mutate: createUser, isPending: isCreating } = useMutation({
|
const {
|
||||||
|
mutate: createUser,
|
||||||
|
isPending: isCreating,
|
||||||
|
isSuccess,
|
||||||
|
} = useMutation({
|
||||||
mutationFn: createUserFn,
|
mutationFn: createUserFn,
|
||||||
onSuccess: (user) => {
|
onSuccess: (user) => {
|
||||||
toast.success(ADD_SUCCESS);
|
toast.success(ADD_SUCCESS);
|
||||||
@@ -33,7 +37,7 @@ const useCreateUser = () => {
|
|||||||
onError: (err) => toast.error(err.message),
|
onError: (err) => toast.error(err.message),
|
||||||
});
|
});
|
||||||
|
|
||||||
return { isCreating, createUser };
|
return { isCreating, createUser, isSuccess };
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useCreateUser };
|
export { useCreateUser };
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useMutation, useQueryClient } from '@tanstack/react-query';
|
|||||||
// Services
|
// Services
|
||||||
import { updateUser as updateUserFn } from '@service/userServices';
|
import { updateUser as updateUserFn } from '@service/userServices';
|
||||||
|
|
||||||
// Messages
|
// Constants
|
||||||
import { UPDATE_SUCCESS } from '@constant/messages';
|
import { UPDATE_SUCCESS } from '@constant/messages';
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
@@ -18,7 +18,11 @@ const useUpdateUser = () => {
|
|||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { dispatch } = useUserRoomAvailable();
|
const { dispatch } = useUserRoomAvailable();
|
||||||
|
|
||||||
const { mutate: updateUser, isPending: isUpdating } = useMutation({
|
const {
|
||||||
|
mutate: updateUser,
|
||||||
|
isPending: isUpdating,
|
||||||
|
isSuccess,
|
||||||
|
} = useMutation({
|
||||||
mutationFn: updateUserFn,
|
mutationFn: updateUserFn,
|
||||||
onSuccess: (user) => {
|
onSuccess: (user) => {
|
||||||
toast.success(UPDATE_SUCCESS);
|
toast.success(UPDATE_SUCCESS);
|
||||||
@@ -33,7 +37,7 @@ const useUpdateUser = () => {
|
|||||||
onError: (err) => toast.error(err.message),
|
onError: (err) => toast.error(err.message),
|
||||||
});
|
});
|
||||||
|
|
||||||
return { isUpdating, updateUser };
|
return { isUpdating, updateUser, isSuccess };
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useUpdateUser };
|
export { useUpdateUser };
|
||||||
|
|||||||
@@ -1,34 +1,78 @@
|
|||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
import { getAllUsers } from '@service/userServices';
|
import { getAllUsers } from '@service/userServices';
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { DEFAULT_PAGE_SIZE } from '@constant/config';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch data of users from database
|
* Fetch data of users from database
|
||||||
* @returns The status of loading users and data of users
|
* @returns The status of loading users and data of users
|
||||||
*/
|
*/
|
||||||
const useUsers = () => {
|
const useUsers = () => {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const sortByValue = searchParams.get('sortBy') || 'id';
|
const sortByValue = searchParams.get('sortBy') || 'id';
|
||||||
const orderByValue = searchParams.get('orderBy') || 'asc';
|
const orderByValue = searchParams.get('orderBy') || 'asc';
|
||||||
const phoneSearch = searchParams.get('search') || '';
|
const searchValue = searchParams.get('search') || '';
|
||||||
|
const page = searchParams.get('page') ? Number(searchParams.get('page')) : 1;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isLoading,
|
isLoading,
|
||||||
data: users,
|
data: { data: users, count } = {},
|
||||||
error,
|
error,
|
||||||
} = useQuery({
|
} = useQuery({
|
||||||
queryKey: ['users', sortByValue, orderByValue, phoneSearch],
|
queryKey: ['users', sortByValue, orderByValue, searchValue, page],
|
||||||
queryFn: () => getAllUsers(sortByValue, orderByValue, phoneSearch),
|
queryFn: () =>
|
||||||
|
getAllUsers({
|
||||||
|
sortBy: sortByValue,
|
||||||
|
orderBy: orderByValue,
|
||||||
|
phoneSearch: searchValue,
|
||||||
|
page,
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
toast.error(error.message);
|
toast.error(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return { isLoading, users };
|
// Pre-fetching
|
||||||
|
const totalPage = Math.ceil(count! / DEFAULT_PAGE_SIZE);
|
||||||
|
|
||||||
|
if (page < totalPage) {
|
||||||
|
const nextPage = page + 1;
|
||||||
|
|
||||||
|
queryClient.prefetchQuery({
|
||||||
|
queryKey: ['users', sortByValue, orderByValue, searchValue, nextPage],
|
||||||
|
queryFn: () =>
|
||||||
|
getAllUsers({
|
||||||
|
sortBy: sortByValue,
|
||||||
|
orderBy: orderByValue,
|
||||||
|
phoneSearch: searchValue,
|
||||||
|
page: nextPage,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page > 1) {
|
||||||
|
const previousPage = page - 1;
|
||||||
|
|
||||||
|
queryClient.prefetchQuery({
|
||||||
|
queryKey: ['users', sortByValue, orderByValue, searchValue, previousPage],
|
||||||
|
queryFn: () =>
|
||||||
|
getAllUsers({
|
||||||
|
sortBy: sortByValue,
|
||||||
|
orderBy: orderByValue,
|
||||||
|
phoneSearch: searchValue,
|
||||||
|
page: previousPage,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return { isLoading, users, count };
|
||||||
};
|
};
|
||||||
|
|
||||||
export { useUsers };
|
export { useUsers };
|
||||||
|
|||||||
@@ -6,24 +6,38 @@ import { IDataState } from '@type/common';
|
|||||||
import supabase from './supabaseService';
|
import supabase from './supabaseService';
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
|
import { DEFAULT_PAGE_SIZE } from '@constant/config';
|
||||||
|
|
||||||
const ROOMS_TABLE = 'rooms';
|
const ROOMS_TABLE = 'rooms';
|
||||||
const ERROR_FETCHING = "Can't fetch room data!";
|
const ERROR_FETCHING = "Can't fetch room data!";
|
||||||
const ERROR_UPDATE_ROOM = "Can't update room!";
|
const ERROR_UPDATE_ROOM = "Can't update room!";
|
||||||
const ERROR_CREATE_ROOM = "Can't create room!";
|
const ERROR_CREATE_ROOM = "Can't create room!";
|
||||||
const ERROR_DELETE_ROOM = "Can't delete room!";
|
const ERROR_DELETE_ROOM = "Can't delete room!";
|
||||||
|
|
||||||
|
interface IGetAllRooms {
|
||||||
|
sortBy: string;
|
||||||
|
orderBy: string;
|
||||||
|
roomName: string;
|
||||||
|
page: number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all rooms from database
|
* Get all rooms from database
|
||||||
* @returns Return all rooms in database
|
* @returns Return all rooms in database
|
||||||
*/
|
*/
|
||||||
const getAllRooms = async (
|
const getAllRooms = async ({
|
||||||
sortBy: string,
|
sortBy,
|
||||||
orderBy: string,
|
orderBy,
|
||||||
roomName: string
|
roomName,
|
||||||
): Promise<IRoom[]> => {
|
page,
|
||||||
const { data, error } = await supabase
|
}: IGetAllRooms): Promise<{ data: IRoom[]; count: number | null }> => {
|
||||||
|
const from = (page - 1) * DEFAULT_PAGE_SIZE;
|
||||||
|
const to = from + DEFAULT_PAGE_SIZE - 1;
|
||||||
|
|
||||||
|
const { data, error, count } = await supabase
|
||||||
.from(ROOMS_TABLE)
|
.from(ROOMS_TABLE)
|
||||||
.select('*')
|
.select('*', { count: 'exact' })
|
||||||
|
.range(from, to)
|
||||||
.order(sortBy, { ascending: orderBy === 'asc' })
|
.order(sortBy, { ascending: orderBy === 'asc' })
|
||||||
.ilike('name', `%${roomName}%`);
|
.ilike('name', `%${roomName}%`);
|
||||||
|
|
||||||
@@ -32,7 +46,7 @@ const getAllRooms = async (
|
|||||||
throw new Error(ERROR_FETCHING);
|
throw new Error(ERROR_FETCHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return { data, count };
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import { IDataState } from '@type/common';
|
|||||||
// Services
|
// Services
|
||||||
import supabase from './supabaseService';
|
import supabase from './supabaseService';
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
import { DEFAULT_PAGE_SIZE } from '@constant/config';
|
||||||
|
|
||||||
const USERS_TABLE = 'users';
|
const USERS_TABLE = 'users';
|
||||||
const ERROR_FETCHING = "Users can't be loaded!";
|
const ERROR_FETCHING = "Users can't be loaded!";
|
||||||
const ERROR_CREATE_USER = "Can't create user!";
|
const ERROR_CREATE_USER = "Can't create user!";
|
||||||
@@ -49,6 +52,13 @@ const updateUser = async (user: IUser): Promise<IUser> => {
|
|||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface IGetAllUsers {
|
||||||
|
sortBy: string;
|
||||||
|
orderBy: string;
|
||||||
|
phoneSearch: string;
|
||||||
|
page: number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return data of users from database
|
* Return data of users from database
|
||||||
* @param sortBy Sort by column
|
* @param sortBy Sort by column
|
||||||
@@ -56,14 +66,19 @@ const updateUser = async (user: IUser): Promise<IUser> => {
|
|||||||
* @param phoneSearch The phone need to be search
|
* @param phoneSearch The phone need to be search
|
||||||
* @returns The data of users from database
|
* @returns The data of users from database
|
||||||
*/
|
*/
|
||||||
const getAllUsers = async (
|
const getAllUsers = async ({
|
||||||
sortBy: string,
|
sortBy,
|
||||||
orderBy: string,
|
orderBy,
|
||||||
phoneSearch: string
|
phoneSearch,
|
||||||
): Promise<IUser[]> => {
|
page,
|
||||||
const { data, error } = await supabase
|
}: IGetAllUsers): Promise<{ data: IUser[]; count: number | null }> => {
|
||||||
|
const from = (page - 1) * DEFAULT_PAGE_SIZE;
|
||||||
|
const to = from + DEFAULT_PAGE_SIZE - 1;
|
||||||
|
|
||||||
|
const { data, error, count } = await supabase
|
||||||
.from(USERS_TABLE)
|
.from(USERS_TABLE)
|
||||||
.select('*')
|
.select('*', { count: 'exact' })
|
||||||
|
.range(from, to)
|
||||||
.order(sortBy, { ascending: orderBy === 'asc' })
|
.order(sortBy, { ascending: orderBy === 'asc' })
|
||||||
.ilike('phone', `%${phoneSearch}%`);
|
.ilike('phone', `%${phoneSearch}%`);
|
||||||
|
|
||||||
@@ -72,7 +87,7 @@ const getAllUsers = async (
|
|||||||
throw new Error(ERROR_FETCHING);
|
throw new Error(ERROR_FETCHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return { data, count };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getUserNotBooked = async (): Promise<IDataState[]> => {
|
const getUserNotBooked = async (): Promise<IDataState[]> => {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
--header-table-color: #ebebeb;
|
--header-table-color: #ebebeb;
|
||||||
--border-color: #8c8c8c;
|
--border-color: #8c8c8c;
|
||||||
|
--footer-table-color: #ebebeb;
|
||||||
|
|
||||||
--secondary-btn-color: #d1d1d1;
|
--secondary-btn-color: #d1d1d1;
|
||||||
--disabled-btn-color: #7f82a6;
|
--disabled-btn-color: #7f82a6;
|
||||||
|
|||||||
Reference in New Issue
Block a user