From fad2380cfb048010677ee03bf2385cc0f27850e5 Mon Sep 17 00:00:00 2001 From: Loi Phan Date: Mon, 20 Nov 2023 19:46:35 +0700 Subject: [PATCH] Update hooks and services --- .../src/hooks/rooms/useCreateRoom.ts | 29 +++ .../src/hooks/rooms/useDeleteRoom.ts | 31 +++ hotel-management/src/hooks/rooms/useRooms.ts | 34 +++ .../src/hooks/rooms/useUpdateRoom.ts | 29 +++ hotel-management/src/hooks/useFetch.ts | 77 ------- hotel-management/src/hooks/useForwardRef.ts | 25 --- .../src/hooks/users/useCreateUser.ts | 29 +++ .../src/hooks/users/useUpdateUser.ts | 29 +++ hotel-management/src/hooks/users/useUsers.ts | 34 +++ hotel-management/src/services/roomServices.ts | 199 +++++------------- .../src/services/supabaseService.ts | 9 + hotel-management/src/services/userServices.ts | 107 ++++------ 12 files changed, 321 insertions(+), 311 deletions(-) create mode 100644 hotel-management/src/hooks/rooms/useCreateRoom.ts create mode 100644 hotel-management/src/hooks/rooms/useDeleteRoom.ts create mode 100644 hotel-management/src/hooks/rooms/useRooms.ts create mode 100644 hotel-management/src/hooks/rooms/useUpdateRoom.ts delete mode 100644 hotel-management/src/hooks/useFetch.ts delete mode 100644 hotel-management/src/hooks/useForwardRef.ts create mode 100644 hotel-management/src/hooks/users/useCreateUser.ts create mode 100644 hotel-management/src/hooks/users/useUpdateUser.ts create mode 100644 hotel-management/src/hooks/users/useUsers.ts create mode 100644 hotel-management/src/services/supabaseService.ts diff --git a/hotel-management/src/hooks/rooms/useCreateRoom.ts b/hotel-management/src/hooks/rooms/useCreateRoom.ts new file mode 100644 index 0000000..570992f --- /dev/null +++ b/hotel-management/src/hooks/rooms/useCreateRoom.ts @@ -0,0 +1,29 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import toast from 'react-hot-toast'; + +// Services +import { createRoom as createRoomFn } from '@service/roomServices'; + +// Constants +import { ADD_SUCCESS } from '@constant/messages'; + +/** + * Create room on database + * @returns The boolean of isCreating and create room function + */ +const useCreateRoom = () => { + const queryClient = useQueryClient(); + + const { mutate: createRoom, isPending: isCreating } = useMutation({ + mutationFn: createRoomFn, + onSuccess: () => { + toast.success(ADD_SUCCESS); + queryClient.invalidateQueries({ queryKey: ['rooms'] }); + }, + onError: (err) => toast.error(err.message), + }); + + return { isCreating, createRoom }; +}; + +export { useCreateRoom }; diff --git a/hotel-management/src/hooks/rooms/useDeleteRoom.ts b/hotel-management/src/hooks/rooms/useDeleteRoom.ts new file mode 100644 index 0000000..693d3d3 --- /dev/null +++ b/hotel-management/src/hooks/rooms/useDeleteRoom.ts @@ -0,0 +1,31 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import toast from 'react-hot-toast'; + +// Services +import { deleteRoom as deleteRoomFn } from '@service/roomServices'; + +// Constants +import * as messages from '@constant/messages'; + +/** + * Delete the room from database + * @returns The boolean of status deleting and deleteRoom function + */ +const useDeleteRoom = () => { + const queryClient = useQueryClient(); + + const { isPending: isDeleting, mutate: deleteRoom } = useMutation({ + mutationFn: deleteRoomFn, + onSuccess: () => { + toast.success(messages.DELETE_SUCCESS); + queryClient.invalidateQueries({ + queryKey: ['rooms'], + }); + }, + onError: (err) => toast.error(err.message), + }); + + return { isDeleting, deleteRoom }; +}; + +export { useDeleteRoom }; diff --git a/hotel-management/src/hooks/rooms/useRooms.ts b/hotel-management/src/hooks/rooms/useRooms.ts new file mode 100644 index 0000000..f6ffc75 --- /dev/null +++ b/hotel-management/src/hooks/rooms/useRooms.ts @@ -0,0 +1,34 @@ +import toast from 'react-hot-toast'; +import { useQuery } from '@tanstack/react-query'; +import { useSearchParams } from 'react-router-dom'; + +// Services +import { getAllRooms } from '@service/roomServices'; + +/** + * Fetch room from database + * @returns The status of loading rooms from database and data of rooms + */ +const useRooms = () => { + const [searchParams] = useSearchParams(); + const sortByValue = searchParams.get('sortBy') || 'id'; + const orderByValue = searchParams.get('orderBy') || 'asc'; + const phoneSearch = searchParams.get('search') || ''; + + const { + isLoading, + data: rooms, + error, + } = useQuery({ + queryKey: ['rooms', sortByValue, orderByValue, phoneSearch], + queryFn: () => getAllRooms(sortByValue, orderByValue, phoneSearch), + }); + + if (error) { + toast.error(error.message); + } + + return { isLoading, rooms }; +}; + +export { useRooms }; diff --git a/hotel-management/src/hooks/rooms/useUpdateRoom.ts b/hotel-management/src/hooks/rooms/useUpdateRoom.ts new file mode 100644 index 0000000..ab6bdb4 --- /dev/null +++ b/hotel-management/src/hooks/rooms/useUpdateRoom.ts @@ -0,0 +1,29 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import toast from 'react-hot-toast'; + +// Services +import { updateRoom as updateRoomFn } from '@service/roomServices'; + +// Constants +import { UPDATE_SUCCESS } from '@constant/messages'; + +/** + * Update room from database + * @returns The status of updating and updateRoom function + */ +const useUpdateRoom = () => { + const queryClient = useQueryClient(); + + const { mutate: updateRoom, isPending: isUpdating } = useMutation({ + mutationFn: updateRoomFn, + onSuccess: () => { + toast.success(UPDATE_SUCCESS); + queryClient.invalidateQueries({ queryKey: ['rooms'] }); + }, + onError: (err) => toast.error(err.message), + }); + + return { isUpdating, updateRoom }; +}; + +export { useUpdateRoom }; diff --git a/hotel-management/src/hooks/useFetch.ts b/hotel-management/src/hooks/useFetch.ts deleted file mode 100644 index 39b6b02..0000000 --- a/hotel-management/src/hooks/useFetch.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { useEffect, useState } from 'react'; - -// Constants -import { BASE_URL } from '@constant/path'; -import { DEFAULT_ORDER_BY, DEFAULT_SORT_BY } from '@constant/config'; - -// Helpers -import { searchQuery } from '@helper/helper'; - -// Types -import { Nullable } from '@type/common'; - -/** - * The function use to fetch data on server API. - * @param path The path of url - * @param columnSearch Column need to search - * @param keyWord The key word to search - * @param tempSortBy Sort by - * @param tempOrderBy Order by - * @param reload Fetch again - * @returns data: A data after fetch, isPending: A boolean indicating whether or not the progress of fetch data is done, errorMsg: A error message from the server. - */ -const useFetch = ( - path: string, - columnSearch: string = '', - keyWord: string = '', - tempSortBy?: string, - tempOrderBy?: string, - reload?: boolean -) => { - const [data, setData] = useState(null); - const [isPending, setIsPending] = useState(false); - const [errorFetchMsg, setErrorFetchMsg] = useState>(null); - - useEffect(() => { - // Clear data - setData(null); - - const fetchData = async () => { - setIsPending(true); - - // Set default value - const sortBy = tempSortBy - ? tempSortBy - : DEFAULT_SORT_BY; - const orderBy = tempOrderBy - ? tempOrderBy - : DEFAULT_ORDER_BY; - - // Query search - const query = searchQuery(columnSearch, keyWord, sortBy, orderBy); - - try { - const response = await fetch(BASE_URL + path + '?' + query); - const json = await response.json(); - - if (!response.ok) { - throw new Error( - `Error code: ${response.status} \n Messages: ${response.text}` - ); - } - - setIsPending(false); - setData(json); - setErrorFetchMsg(null); - } catch (error) { - setErrorFetchMsg(`Could not fetch data.\n ${error}`); - setIsPending(false); - } - }; - - fetchData(); - }, [path, reload, columnSearch, keyWord, tempOrderBy, tempSortBy]); - return { data, isPending, errorFetchMsg }; -}; - -export { useFetch }; diff --git a/hotel-management/src/hooks/useForwardRef.ts b/hotel-management/src/hooks/useForwardRef.ts deleted file mode 100644 index e333401..0000000 --- a/hotel-management/src/hooks/useForwardRef.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ForwardedRef, useEffect, useRef } from 'react'; - -// Types -import { Nullable } from '@type/common'; - -const useForwardRef = ( - ref: ForwardedRef, - initialValue: Nullable = null -) => { - const targetRef = useRef(initialValue); - - useEffect(() => { - if (!ref) return; - - if (typeof ref === 'function') { - ref(targetRef.current); - } else { - ref.current = targetRef.current; - } - }, [ref]); - - return targetRef; -}; - -export { useForwardRef }; diff --git a/hotel-management/src/hooks/users/useCreateUser.ts b/hotel-management/src/hooks/users/useCreateUser.ts new file mode 100644 index 0000000..95e3b35 --- /dev/null +++ b/hotel-management/src/hooks/users/useCreateUser.ts @@ -0,0 +1,29 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import toast from 'react-hot-toast'; + +// Services +import { createUser as createUserFn } from '@service/userServices'; + +// Constants +import { ADD_SUCCESS } from '@constant/messages'; + +/** + * Create user in database + * @returns The status of creating users and createUser function + */ +const useCreateUser = () => { + const queryClient = useQueryClient(); + + const { mutate: createUser, isPending: isCreating } = useMutation({ + mutationFn: createUserFn, + onSuccess: () => { + toast.success(ADD_SUCCESS); + queryClient.invalidateQueries({ queryKey: ['users'] }); + }, + onError: (err) => toast.error(err.message), + }); + + return { isCreating, createUser }; +}; + +export { useCreateUser }; diff --git a/hotel-management/src/hooks/users/useUpdateUser.ts b/hotel-management/src/hooks/users/useUpdateUser.ts new file mode 100644 index 0000000..a06b5aa --- /dev/null +++ b/hotel-management/src/hooks/users/useUpdateUser.ts @@ -0,0 +1,29 @@ +import toast from 'react-hot-toast'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +// Services +import { updateUser as updateUserFn } from '@service/userServices'; + +// Messages +import { UPDATE_SUCCESS } from '@constant/messages'; + +/** + * Update user from database + * @returns The status of updating user and updateUser function + */ +const useUpdateUser = () => { + const queryClient = useQueryClient(); + + const { mutate: updateUser, isPending: isUpdating } = useMutation({ + mutationFn: updateUserFn, + onSuccess: () => { + toast.success(UPDATE_SUCCESS); + queryClient.invalidateQueries({ queryKey: ['users'] }); + }, + onError: (err) => toast.error(err.message), + }); + + return { isUpdating, updateUser }; +}; + +export { useUpdateUser }; diff --git a/hotel-management/src/hooks/users/useUsers.ts b/hotel-management/src/hooks/users/useUsers.ts new file mode 100644 index 0000000..876aa99 --- /dev/null +++ b/hotel-management/src/hooks/users/useUsers.ts @@ -0,0 +1,34 @@ +import toast from 'react-hot-toast'; +import { useQuery } from '@tanstack/react-query'; +import { useSearchParams } from 'react-router-dom'; + +// Services +import { getAllUsers } from '@service/userServices'; + +/** + * Fetch data of users from database + * @returns The status of loading users and data of users + */ +const useUsers = () => { + const [searchParams] = useSearchParams(); + const sortByValue = searchParams.get('sortBy') || 'id'; + const orderByValue = searchParams.get('orderBy') || 'asc'; + const phoneSearch = searchParams.get('search') || ''; + + const { + isLoading, + data: users, + error, + } = useQuery({ + queryKey: ['users', sortByValue, orderByValue, phoneSearch], + queryFn: () => getAllUsers(sortByValue, orderByValue, phoneSearch), + }); + + if (error) { + toast.error(error.message); + } + + return { isLoading, users }; +}; + +export { useUsers }; diff --git a/hotel-management/src/services/roomServices.ts b/hotel-management/src/services/roomServices.ts index 4976142..926e887 100644 --- a/hotel-management/src/services/roomServices.ts +++ b/hotel-management/src/services/roomServices.ts @@ -1,173 +1,82 @@ -import toast from 'react-hot-toast'; - // Types -import { Nullable } from '@type/common'; -import { IResponse } from '@type/responses'; import { IRoom } from '@type/rooms'; -// Helpers -import { sendRequest } from '@helper/sendRequest'; -import { errorMsg } from '@helper/helper'; +// Services +import supabase from './supabaseService'; // Constants -import { STATUS_CODE, RESPONSE_MESSAGE } from '@constant/responseStatus'; -import { ROOM_PATH } from '@constant/path'; +const ROOMS_TABLE = 'rooms'; +const ERROR_FETCHING = "Can't fetch room data!"; +const ERROR_UPDATE_ROOM = "Can't update room!"; +const ERROR_CREATE_ROOM = "Can't create room!"; +const ERROR_DELETE_ROOM = "Can't delete room!"; /** - * Get all rooms from server - * @returns Return all rooms in server + * Get all rooms from database + * @returns Return all rooms in database */ -const getAllRoom = async (): Promise> => { - try { - const response = await sendRequest(ROOM_PATH); +const getAllRooms = async ( + sortBy: string, + orderBy: string, + roomName: string +): Promise => { + const { data, error } = await supabase + .from(ROOMS_TABLE) + .select('*') + .order(sortBy, { ascending: orderBy === 'asc' }) + .like('name', `%${roomName}%`); - if (response.statusCode === STATUS_CODE.OK) { - const rooms = response.data!; - - return rooms; - } else { - throw new Error(errorMsg(response.statusCode, response.msg)); - } - } catch (error) { - if (error instanceof Error) { - toast.error(error.message); - } + if (error) { + console.error(error.message); + throw new Error(ERROR_FETCHING); } - return null; + return data; }; /** - * Get room by id - * @param roomId The id room need to be get - * @returns Return the room object depend on room id - */ -const getRoom = async (roomId: number): Promise> => { - try { - const response = await sendRequest(ROOM_PATH + '/' + roomId); - - if (response.statusCode !== STATUS_CODE.OK) { - throw new Error(errorMsg(response.statusCode, response.msg)); - } - - const rooms = response.data!; - - return rooms; - } catch (error) { - if (error instanceof Error) { - toast.error(error.message); - } - } - - return null; -}; - -/** - * Update room into server + * Update room into database * @param room Room object need to be updated - * @returns The response object */ -const updateRoom = async (room: IRoom): Promise>> => { - try { - const response = await sendRequest( - ROOM_PATH + '/' + room.id, - 'PUT', - JSON.stringify(room) - ); +const updateRoom = async (room: IRoom): Promise => { + const { error } = await supabase + .from(ROOMS_TABLE) + .update(room) + .eq('id', room.id); - return response; - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - } + if (error) { + console.error(error.message); + throw new Error(ERROR_UPDATE_ROOM); } - - return null; }; /** - * Update room status - * @param roomId The id room need to be updated - * @param status Status of room - * @param roomIdNew The new id room need to be updated - * @returns Return the response object - */ -const updateRoomStatus = async ( - roomId: number, - status: boolean, - roomIdNew?: number -): Promise>> => { - try { - if (!roomIdNew) { - const response = await sendRequest( - ROOM_PATH + '/' + roomId, - 'PATCH', - JSON.stringify({ status: status }) - ); - - return response; - } - - // Update new room status - const resNewRoom = await sendRequest( - ROOM_PATH + '/' + roomIdNew, - 'PATCH', - JSON.stringify({ status: status }) - ); - - // Update old room status; - const resOldRoom = await sendRequest( - ROOM_PATH + '/' + roomId, - 'PATCH', - JSON.stringify({ status: !status }) - ); - - if ( - resNewRoom.statusCode === STATUS_CODE.OK && - resOldRoom.statusCode === STATUS_CODE.OK - ) { - return { - statusCode: STATUS_CODE.OK, - msg: RESPONSE_MESSAGE.UPDATE_SUCCESS, - }; - } - } catch (error) { - if (error instanceof Error) { - toast.error(error.message); - } - } - - return null; -}; - -/** - * Add room to server + * Add room to database * @param room The room object need to be add - * @returns The response object if complete or null */ -const addRoom = async (room: IRoom): Promise>> => { - try { - // Set default status room - room.status = false; +const createRoom = async (room: IRoom): Promise => { + // Set default status + room.status = false; - const response = await sendRequest( - ROOM_PATH, - 'POST', - JSON.stringify(room) - ); + const { error } = await supabase.from(ROOMS_TABLE).insert([room]); - if (response.statusCode !== STATUS_CODE.CREATE) { - throw new Error(errorMsg(response.statusCode, response.msg)); - } - - return response; - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - } + if (error) { + console.error(error.message); + throw new Error(ERROR_CREATE_ROOM); } - - return null; }; -export { getRoom, updateRoom, updateRoomStatus, getAllRoom, addRoom }; +/** + * Delete room in database + * @param idRoom The id of room need to delete + */ +const deleteRoom = async (idRoom: number) => { + const { error } = await supabase.from(ROOMS_TABLE).delete().eq('id', idRoom); + + if (error) { + console.error(error.message); + throw new Error(ERROR_DELETE_ROOM); + } +}; + +export { getAllRooms, updateRoom, createRoom, deleteRoom }; diff --git a/hotel-management/src/services/supabaseService.ts b/hotel-management/src/services/supabaseService.ts new file mode 100644 index 0000000..b7e9fcb --- /dev/null +++ b/hotel-management/src/services/supabaseService.ts @@ -0,0 +1,9 @@ +import { createClient } from '@supabase/supabase-js'; +import { Database } from '@type/supabase'; + +// Constants +import { supabaseKey, supabaseUrl } from '@constant/config'; + +const supabase = createClient(supabaseUrl, supabaseKey!); + +export default supabase; diff --git a/hotel-management/src/services/userServices.ts b/hotel-management/src/services/userServices.ts index 94cc7b3..743f99e 100644 --- a/hotel-management/src/services/userServices.ts +++ b/hotel-management/src/services/userServices.ts @@ -1,88 +1,67 @@ -import toast from 'react-hot-toast'; - -// Constants -import { USER_PATH } from '@constant/path'; -import { STATUS_CODE } from '@constant/responseStatus'; - // Types -import { Nullable } from '@type/common'; -import { IResponse } from '@type/responses'; import { IUser } from '@type/users'; -// Helpers -import { sendRequest } from '@helper/sendRequest'; -import { errorMsg } from '@helper/helper'; +// Services +import supabase from './supabaseService'; + +const USERS_TABLE = 'users'; +const ERROR_FETCHING = "Users can't be loaded!"; +const ERROR_CREATE_USER = "Can't create user!"; +const ERROR_UPDATE_USER = "Can't update user!"; /** - * Create user to the server + * Create user to the database * @param user The user object need to be created - * @returns The IResponse object if success or null */ -const createUser = async (user: IUser): Promise>> => { - try { - const response = await sendRequest( - USER_PATH, - 'POST', - JSON.stringify(user) - ); +const createUser = async (user: IUser): Promise => { + const { error } = await supabase.from(USERS_TABLE).insert([user]); - if (response.statusCode !== STATUS_CODE.CREATE) { - throw new Error(errorMsg(response.statusCode, response.msg)); - } - - return response; - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - } + if (error) { + console.error(error.message); + throw new Error(ERROR_CREATE_USER); } - - return null; -} +}; /** - * Update the user to the server + * Update the user to the database * @param user The user object need to be updated - * @returns The IResponse object if update success or null */ -const updateUser = async (user: IUser): Promise>> => { - try { - const response = await sendRequest( - USER_PATH + '/' + user.id, - 'PUT', - JSON.stringify(user) - ); +const updateUser = async (user: IUser): Promise => { + const { error } = await supabase + .from(USERS_TABLE) + .update(user) + .eq('id', user.id); - if (response.statusCode !== STATUS_CODE.OK) { - throw new Error(errorMsg(response.statusCode, response.msg)); - } - - return response; - } catch (error: unknown) { - if (error instanceof Error) { - toast.error(error.message); - } + if (error) { + console.error(error.message); + throw new Error(ERROR_UPDATE_USER); } - - return null; }; /** - * Checkout user - * @param user The user need to be checkout - * @returns The IResponse object if checkout success or not + * Return data of users from database + * @param sortBy Sort by column + * @param orderBy Order by ascending or descending + * @param phoneSearch The phone need to be search + * @returns The data of users from database */ -const checkOutUser = async (user: IUser): Promise>> => { - const tempUser = user; +const getAllUsers = async ( + sortBy: string, + orderBy: string, + phoneSearch: string +): Promise => { + const { data, error } = await supabase + .from(USERS_TABLE) + .select('*') + .order(sortBy, { ascending: orderBy === 'asc' }) + .like('phone', `%${phoneSearch}%`); - if (tempUser) { - tempUser.roomId = 0; - const resUpdateUser = await updateUser(tempUser); - - return resUpdateUser; + if (error) { + console.error(error.message); + throw new Error(ERROR_FETCHING); } - return null; + return data; }; -export { updateUser, checkOutUser, createUser }; +export { updateUser, createUser, getAllUsers };