This commit is contained in:
2026-06-14 13:19:39 +03:00
parent 4a3db42971
commit 19fff3a92f
152 changed files with 10908 additions and 8276 deletions
+6 -6
View File
@@ -1,7 +1,7 @@
export function formatCurrency(amount: number, currency = "KES") {
return new Intl.NumberFormat("en-KE", {
style: "currency",
currency,
maximumFractionDigits: 2,
}).format(amount);
}
return new Intl.NumberFormat("en-KE", {
style: "currency",
currency,
maximumFractionDigits: 2,
}).format(amount);
}
+8 -8
View File
@@ -1,10 +1,10 @@
export function formatDate(value: string | null | undefined) {
if (!value) {
return "—";
}
if (!value) {
return "—";
}
return new Intl.DateTimeFormat("en-KE", {
dateStyle: "medium",
timeStyle: "short",
}).format(new Date(value));
}
return new Intl.DateTimeFormat("en-KE", {
dateStyle: "medium",
timeStyle: "short",
}).format(new Date(value));
}
+15 -13
View File
@@ -1,19 +1,21 @@
import * as React from "react"
import * as React from "react";
const MOBILE_BREAKPOINT = 768
const MOBILE_BREAKPOINT = 768;
export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(undefined)
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
undefined,
);
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
}
mql.addEventListener("change", onChange)
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
return () => mql.removeEventListener("change", onChange)
}, [])
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
};
mql.addEventListener("change", onChange);
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
return () => mql.removeEventListener("change", onChange);
}, []);
return !!isMobile
return !!isMobile;
}
+79 -79
View File
@@ -1,111 +1,111 @@
import {login, logout, register} from "#/api/auth";
import type {AuthUser, LoginRequest, RegisterRequest} from "#/types/auth";
import {useMutation, useQueryClient} from "@tanstack/react-query";
import {createContext, useContext, useState} from "react";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { createContext, useContext, useState } from "react";
import { login, logout, register } from "#/api/auth";
import type { AuthUser, LoginRequest, RegisterRequest } from "#/types/auth";
type AuthContextValue = {
user: AuthUser | null;
isLoading: boolean;
login: (request: LoginRequest) => Promise<AuthUser>;
register: (request: RegisterRequest) => Promise<AuthUser>;
logout: () => Promise<void>;
user: AuthUser | null;
isLoading: boolean;
login: (request: LoginRequest) => Promise<AuthUser>;
register: (request: RegisterRequest) => Promise<AuthUser>;
logout: () => Promise<void>;
};
const AuthContext = createContext<AuthContextValue | null>(null);
const storedUserKey = "cymelle.auth.user";
export const authQueryKeys = {
me: ["auth", "me"] as const,
me: ["auth", "me"] as const,
};
export function AuthProvider({children}: {children: React.ReactNode}) {
const queryClient = useQueryClient();
const [user, setUser] = useState<AuthUser | null>(() => readStoredUser());
export function AuthProvider({ children }: { children: React.ReactNode }) {
const queryClient = useQueryClient();
const [user, setUser] = useState<AuthUser | null>(() => readStoredUser());
const loginMutation = useMutation({
mutationFn: login,
onSuccess: (user) => {
queryClient.clear();
persistUser(user);
setUser(user);
queryClient.setQueryData(authQueryKeys.me, user);
},
});
const loginMutation = useMutation({
mutationFn: login,
onSuccess: (user) => {
queryClient.clear();
persistUser(user);
setUser(user);
queryClient.setQueryData(authQueryKeys.me, user);
},
});
const registerMutation = useMutation({
mutationFn: register,
onSuccess: (user) => {
queryClient.clear();
persistUser(user);
setUser(user);
queryClient.setQueryData(authQueryKeys.me, user);
},
});
const registerMutation = useMutation({
mutationFn: register,
onSuccess: (user) => {
queryClient.clear();
persistUser(user);
setUser(user);
queryClient.setQueryData(authQueryKeys.me, user);
},
});
const logoutMutation = useMutation({
mutationFn: logout,
onSettled: () => {
persistUser(null);
setUser(null);
queryClient.clear();
},
});
const logoutMutation = useMutation({
mutationFn: logout,
onSettled: () => {
persistUser(null);
setUser(null);
queryClient.clear();
},
});
async function logoutUser() {
persistUser(null);
setUser(null);
queryClient.clear();
await logoutMutation.mutateAsync().catch(() => undefined);
}
async function logoutUser() {
persistUser(null);
setUser(null);
queryClient.clear();
await logoutMutation.mutateAsync().catch(() => undefined);
}
const value: AuthContextValue = {
user,
isLoading: false,
login: loginMutation.mutateAsync,
register: registerMutation.mutateAsync,
logout: logoutUser,
};
const value: AuthContextValue = {
user,
isLoading: false,
login: loginMutation.mutateAsync,
register: registerMutation.mutateAsync,
logout: logoutUser,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
}
export function useAuth() {
const context = useContext(AuthContext);
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within AuthProvider");
}
if (!context) {
throw new Error("useAuth must be used within AuthProvider");
}
return context;
return context;
}
function readStoredUser() {
if (typeof window === "undefined") {
return null;
}
if (typeof window === "undefined") {
return null;
}
const raw = window.localStorage.getItem(storedUserKey);
if (!raw) {
return null;
}
const raw = window.localStorage.getItem(storedUserKey);
if (!raw) {
return null;
}
try {
return JSON.parse(raw) as AuthUser;
} catch {
window.localStorage.removeItem(storedUserKey);
return null;
}
try {
return JSON.parse(raw) as AuthUser;
} catch {
window.localStorage.removeItem(storedUserKey);
return null;
}
}
function persistUser(user: AuthUser | null) {
if (typeof window === "undefined") {
return;
}
if (typeof window === "undefined") {
return;
}
if (!user) {
window.localStorage.removeItem(storedUserKey);
return;
}
if (!user) {
window.localStorage.removeItem(storedUserKey);
return;
}
window.localStorage.setItem(storedUserKey, JSON.stringify(user));
window.localStorage.setItem(storedUserKey, JSON.stringify(user));
}
+110 -91
View File
@@ -1,121 +1,140 @@
import type {Product} from "#/types/product";
import {createContext, useContext, useEffect, useMemo, useState} from "react";
import { createContext, useContext, useEffect, useMemo, useState } from "react";
import type { Product } from "#/types/product";
export type CartItem = {
product: Product;
quantity: number;
product: Product;
quantity: number;
};
type CartContextValue = {
items: CartItem[];
itemCount: number;
totalAmount: number;
currency: string;
addItem: (product: Product, quantity: number) => void;
updateQuantity: (productId: string, quantity: number) => void;
removeItem: (productId: string) => void;
clearCart: () => void;
items: CartItem[];
itemCount: number;
totalAmount: number;
currency: string;
addItem: (product: Product, quantity: number) => void;
updateQuantity: (productId: string, quantity: number) => void;
removeItem: (productId: string) => void;
clearCart: () => void;
};
const CartContext = createContext<CartContextValue | null>(null);
const CART_STORAGE_KEY = "cymelle_cart";
export function CartProvider({children}: {children: React.ReactNode}) {
const [items, setItems] = useState<CartItem[]>(() => {
if (typeof window === "undefined") {
return [];
}
export function CartProvider({ children }: { children: React.ReactNode }) {
const [items, setItems] = useState<CartItem[]>(() => {
if (typeof window === "undefined") {
return [];
}
try {
return JSON.parse(window.localStorage.getItem(CART_STORAGE_KEY) ?? "[]") as CartItem[];
} catch {
return [];
}
});
try {
return JSON.parse(
window.localStorage.getItem(CART_STORAGE_KEY) ?? "[]",
) as CartItem[];
} catch {
return [];
}
});
const itemCount = useMemo(
() => items.reduce((total, item) => total + item.quantity, 0),
[items],
);
const itemCount = useMemo(
() => items.reduce((total, item) => total + item.quantity, 0),
[items],
);
const totalAmount = useMemo(
() => items.reduce((total, item) => total + item.product.price * item.quantity, 0),
[items],
);
const totalAmount = useMemo(
() =>
items.reduce(
(total, item) => total + item.product.price * item.quantity,
0,
),
[items],
);
const currency = items[0]?.product.currency ?? "KES";
const currency = items[0]?.product.currency ?? "KES";
useEffect(() => {
window.localStorage.setItem(CART_STORAGE_KEY, JSON.stringify(items));
}, [items]);
useEffect(() => {
window.localStorage.setItem(CART_STORAGE_KEY, JSON.stringify(items));
}, [items]);
function addItem(product: Product, quantity: number) {
const safeQuantity = Math.min(Math.max(quantity, 1), product.availableQuantity);
function addItem(product: Product, quantity: number) {
const safeQuantity = Math.min(
Math.max(quantity, 1),
product.availableQuantity,
);
setItems((currentItems) => {
const existing = currentItems.find((item) => item.product.id === product.id);
setItems((currentItems) => {
const existing = currentItems.find(
(item) => item.product.id === product.id,
);
if (existing) {
return currentItems.map((item) =>
item.product.id === product.id
? {
...item,
product,
quantity: Math.min(item.quantity + safeQuantity, product.availableQuantity),
}
: item,
);
}
if (existing) {
return currentItems.map((item) =>
item.product.id === product.id
? {
...item,
product,
quantity: Math.min(
item.quantity + safeQuantity,
product.availableQuantity,
),
}
: item,
);
}
return [...currentItems, {product, quantity: safeQuantity}];
});
}
return [...currentItems, { product, quantity: safeQuantity }];
});
}
function updateQuantity(productId: string, quantity: number) {
setItems((currentItems) =>
currentItems.flatMap((item) => {
if (item.product.id !== productId) {
return [item];
}
function updateQuantity(productId: string, quantity: number) {
setItems((currentItems) =>
currentItems.flatMap((item) => {
if (item.product.id !== productId) {
return [item];
}
const nextQuantity = Math.min(Math.max(quantity, 0), item.product.availableQuantity);
return nextQuantity === 0 ? [] : [{...item, quantity: nextQuantity}];
}),
);
}
const nextQuantity = Math.min(
Math.max(quantity, 0),
item.product.availableQuantity,
);
return nextQuantity === 0 ? [] : [{ ...item, quantity: nextQuantity }];
}),
);
}
function removeItem(productId: string) {
setItems((currentItems) => currentItems.filter((item) => item.product.id !== productId));
}
function removeItem(productId: string) {
setItems((currentItems) =>
currentItems.filter((item) => item.product.id !== productId),
);
}
function clearCart() {
setItems([]);
}
function clearCart() {
setItems([]);
}
return (
<CartContext.Provider
value={{
items,
itemCount,
totalAmount,
currency,
addItem,
updateQuantity,
removeItem,
clearCart,
}}
>
{children}
</CartContext.Provider>
);
return (
<CartContext.Provider
value={{
items,
itemCount,
totalAmount,
currency,
addItem,
updateQuantity,
removeItem,
clearCart,
}}
>
{children}
</CartContext.Provider>
);
}
export function useCart() {
const context = useContext(CartContext);
const context = useContext(CartContext);
if (!context) {
throw new Error("useCart must be used within CartProvider");
}
if (!context) {
throw new Error("useCart must be used within CartProvider");
}
return context;
return context;
}
@@ -1,14 +1,14 @@
import {calculateFare} from "#/api/fare";
import {useMutation} from "@tanstack/react-query";
import { useMutation } from "@tanstack/react-query";
import { calculateFare } from "#/api/fare";
type FareCalculationInput = {
distanceKm: number;
surgeMultiplier?: number;
distanceKm: number;
surgeMultiplier?: number;
};
export function useFareCalculation() {
return useMutation({
mutationFn: ({distanceKm, surgeMultiplier}: FareCalculationInput) =>
calculateFare(distanceKm, surgeMultiplier),
});
}
return useMutation({
mutationFn: ({ distanceKm, surgeMultiplier }: FareCalculationInput) =>
calculateFare(distanceKm, surgeMultiplier),
});
}
+15 -15
View File
@@ -1,23 +1,23 @@
import {getInventory, getLowStockInventory} from "#/api/inventory";
import {useQuery} from "@tanstack/react-query";
import { useQuery } from "@tanstack/react-query";
import { getInventory, getLowStockInventory } from "#/api/inventory";
export const inventoryQueryKeys = {
all: ["inventory"] as const,
list: () => [...inventoryQueryKeys.all, "list"] as const,
lowStock: (threshold?: number) =>
[...inventoryQueryKeys.all, "low-stock", threshold ?? "default"] as const,
all: ["inventory"] as const,
list: () => [...inventoryQueryKeys.all, "list"] as const,
lowStock: (threshold?: number) =>
[...inventoryQueryKeys.all, "low-stock", threshold ?? "default"] as const,
};
export function useInventory() {
return useQuery({
queryKey: inventoryQueryKeys.list(),
queryFn: ({signal}) => getInventory(signal),
});
return useQuery({
queryKey: inventoryQueryKeys.list(),
queryFn: ({ signal }) => getInventory(signal),
});
}
export function useLowStockInventory(threshold?: number) {
return useQuery({
queryKey: inventoryQueryKeys.lowStock(threshold),
queryFn: ({signal}) => getLowStockInventory(threshold, signal),
});
}
return useQuery({
queryKey: inventoryQueryKeys.lowStock(threshold),
queryFn: ({ signal }) => getLowStockInventory(threshold, signal),
});
}
+57 -46
View File
@@ -1,64 +1,75 @@
import {cancelOrder, createOrder, getOrders, updateOrderStatus} from "#/api/orders";
import {inventoryQueryKeys} from "#/hooks/useInventory";
import {productQueryKeys} from "#/hooks/useProducts";
import type {OrderFilters} from "#/types/order";
import {useMutation, useQuery, useQueryClient} from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
cancelOrder,
createOrder,
getOrders,
updateOrderStatus,
} from "#/api/orders";
import { inventoryQueryKeys } from "#/hooks/useInventory";
import { productQueryKeys } from "#/hooks/useProducts";
import type { OrderFilters } from "#/types/order";
export const orderQueryKeys = {
all: ["orders"] as const,
list: (filters: OrderFilters, page = 0, size = 20) =>
[...orderQueryKeys.all, "list", filters, page, size] as const,
all: ["orders"] as const,
list: (filters: OrderFilters, page = 0, size = 20) =>
[...orderQueryKeys.all, "list", filters, page, size] as const,
};
export function useOrders(filters: OrderFilters, page = 0, size = 20) {
return useQuery({
queryKey: orderQueryKeys.list(filters, page, size),
queryFn: ({signal}) => getOrders(filters, page, size, signal),
});
return useQuery({
queryKey: orderQueryKeys.list(filters, page, size),
queryFn: ({ signal }) => getOrders(filters, page, size, signal),
});
}
export function useCancelOrder() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: cancelOrder,
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({
queryKey: orderQueryKeys.all,
}),
queryClient.invalidateQueries({
queryKey: inventoryQueryKeys.all,
}),
queryClient.invalidateQueries({
queryKey: productQueryKeys.all,
}),
]);
},
});
return useMutation({
mutationFn: cancelOrder,
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({
queryKey: orderQueryKeys.all,
}),
queryClient.invalidateQueries({
queryKey: inventoryQueryKeys.all,
}),
queryClient.invalidateQueries({
queryKey: productQueryKeys.all,
}),
]);
},
});
}
export function useCreateOrder() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: createOrder,
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({queryKey: orderQueryKeys.all}),
queryClient.invalidateQueries({queryKey: inventoryQueryKeys.all}),
queryClient.invalidateQueries({queryKey: productQueryKeys.all}),
]);
},
});
return useMutation({
mutationFn: createOrder,
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({ queryKey: orderQueryKeys.all }),
queryClient.invalidateQueries({ queryKey: inventoryQueryKeys.all }),
queryClient.invalidateQueries({ queryKey: productQueryKeys.all }),
]);
},
});
}
export function useUpdateOrderStatus() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({id, status}: {id: string; status: import("#/types/order").OrderStatus}) =>
updateOrderStatus(id, status),
onSuccess: () => queryClient.invalidateQueries({queryKey: orderQueryKeys.all}),
});
return useMutation({
mutationFn: ({
id,
status,
}: {
id: string;
status: import("#/types/order").OrderStatus;
}) => updateOrderStatus(id, status),
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: orderQueryKeys.all }),
});
}
+61
View File
@@ -0,0 +1,61 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
getCheckoutQuote,
initializePaystackPayment,
verifyPaystackPayment,
} from "#/api/payments";
import { inventoryQueryKeys } from "#/hooks/useInventory";
import { orderQueryKeys } from "#/hooks/useOrders";
import { productQueryKeys } from "#/hooks/useProducts";
import type {
CheckoutQuoteRequest,
PaystackInitializeRequest,
} from "#/types/payment";
export const paymentQueryKeys = {
all: ["payments"] as const,
quote: (request: CheckoutQuoteRequest) =>
[...paymentQueryKeys.all, "quote", request] as const,
};
export function useCheckoutQuote(
request: CheckoutQuoteRequest,
enabled: boolean,
) {
return useQuery({
queryKey: paymentQueryKeys.quote(request),
queryFn: ({ signal }) => getCheckoutQuote(request, signal),
enabled,
});
}
export function useInitializePaystackPayment() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (request: PaystackInitializeRequest) =>
initializePaystackPayment(request),
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({ queryKey: orderQueryKeys.all }),
queryClient.invalidateQueries({ queryKey: inventoryQueryKeys.all }),
queryClient.invalidateQueries({ queryKey: productQueryKeys.all }),
]);
},
});
}
export function useVerifyPaystackPayment() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: verifyPaystackPayment,
onSuccess: async () => {
await Promise.all([
queryClient.invalidateQueries({ queryKey: orderQueryKeys.all }),
queryClient.invalidateQueries({ queryKey: inventoryQueryKeys.all }),
queryClient.invalidateQueries({ queryKey: productQueryKeys.all }),
]);
},
});
}
+38 -29
View File
@@ -1,50 +1,59 @@
import {createProduct, deactivateProduct, getProduct, getProducts, updateProduct} from "#/api/products";
import type {ProductRequest} from "#/types/product";
import {useMutation, useQuery, useQueryClient} from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
createProduct,
deactivateProduct,
getProduct,
getProducts,
updateProduct,
} from "#/api/products";
import type { ProductRequest } from "#/types/product";
export const productQueryKeys = {
all: ["products"] as const,
detail: (id: string) => [...productQueryKeys.all, "detail", id] as const,
all: ["products"] as const,
detail: (id: string) => [...productQueryKeys.all, "detail", id] as const,
};
export function useProducts() {
return useQuery({
queryKey: productQueryKeys.all,
queryFn: ({signal}) => getProducts(signal),
});
return useQuery({
queryKey: productQueryKeys.all,
queryFn: ({ signal }) => getProducts(signal),
});
}
export function useProduct(id: string) {
return useQuery({
queryKey: productQueryKeys.detail(id),
queryFn: ({signal}) => getProduct(id, signal),
});
return useQuery({
queryKey: productQueryKeys.detail(id),
queryFn: ({ signal }) => getProduct(id, signal),
});
}
export function useCreateProduct() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: createProduct,
onSuccess: () => queryClient.invalidateQueries({queryKey: productQueryKeys.all}),
});
return useMutation({
mutationFn: createProduct,
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: productQueryKeys.all }),
});
}
export function useUpdateProduct() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({id, request}: {id: string; request: ProductRequest}) =>
updateProduct(id, request),
onSuccess: () => queryClient.invalidateQueries({queryKey: productQueryKeys.all}),
});
return useMutation({
mutationFn: ({ id, request }: { id: string; request: ProductRequest }) =>
updateProduct(id, request),
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: productQueryKeys.all }),
});
}
export function useDeactivateProduct() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: deactivateProduct,
onSuccess: () => queryClient.invalidateQueries({queryKey: productQueryKeys.all}),
});
return useMutation({
mutationFn: deactivateProduct,
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: productQueryKeys.all }),
});
}
+44 -39
View File
@@ -1,67 +1,72 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
acceptRide,
cancelRide,
completeRide,
getRides,
requestRide,
updateRideStatus,
acceptRide,
cancelRide,
completeRide,
getRides,
requestRide,
updateRideStatus,
} from "#/api/rides";
import type {CreateRideRequest, RideStatus} from "#/types/ride";
import {useMutation, useQuery, useQueryClient} from "@tanstack/react-query";
import type { CreateRideRequest, RideStatus } from "#/types/ride";
export const rideQueryKeys = {
all: ["rides"] as const,
all: ["rides"] as const,
};
export function useRides() {
return useQuery({
queryKey: rideQueryKeys.all,
queryFn: ({signal}) => getRides(signal),
});
return useQuery({
queryKey: rideQueryKeys.all,
queryFn: ({ signal }) => getRides(signal),
});
}
export function useRequestRide() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: (request: CreateRideRequest) => requestRide(request),
onSuccess: () => queryClient.invalidateQueries({queryKey: rideQueryKeys.all}),
});
return useMutation({
mutationFn: (request: CreateRideRequest) => requestRide(request),
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: rideQueryKeys.all }),
});
}
export function useAcceptRide() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: acceptRide,
onSuccess: () => queryClient.invalidateQueries({queryKey: rideQueryKeys.all}),
});
return useMutation({
mutationFn: acceptRide,
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: rideQueryKeys.all }),
});
}
export function useCompleteRide() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: completeRide,
onSuccess: () => queryClient.invalidateQueries({queryKey: rideQueryKeys.all}),
});
return useMutation({
mutationFn: completeRide,
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: rideQueryKeys.all }),
});
}
export function useCancelRide() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: cancelRide,
onSuccess: () => queryClient.invalidateQueries({queryKey: rideQueryKeys.all}),
});
return useMutation({
mutationFn: cancelRide,
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: rideQueryKeys.all }),
});
}
export function useUpdateRideStatus() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({id, status}: {id: string; status: RideStatus}) =>
updateRideStatus(id, status),
onSuccess: () => queryClient.invalidateQueries({queryKey: rideQueryKeys.all}),
});
return useMutation({
mutationFn: ({ id, status }: { id: string; status: RideStatus }) =>
updateRideStatus(id, status),
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: rideQueryKeys.all }),
});
}
+45 -34
View File
@@ -1,58 +1,69 @@
import {createUser, disableUser, getCustomers, getDrivers, getUsers, updateUser} from "#/api/users";
import type {AdminUserRequest} from "#/types/user";
import {useMutation, useQuery, useQueryClient} from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
createUser,
disableUser,
getCustomers,
getDrivers,
getUsers,
updateUser,
} from "#/api/users";
import type { AdminUserRequest } from "#/types/user";
export const userQueryKeys = {
all: ["users"] as const,
list: () => [...userQueryKeys.all, "list"] as const,
customers: () => [...userQueryKeys.all, "customers"] as const,
drivers: () => [...userQueryKeys.all, "drivers"] as const,
all: ["users"] as const,
list: () => [...userQueryKeys.all, "list"] as const,
customers: () => [...userQueryKeys.all, "customers"] as const,
drivers: () => [...userQueryKeys.all, "drivers"] as const,
};
export function useUsers() {
return useQuery({
queryKey: userQueryKeys.list(),
queryFn: ({signal}) => getUsers(signal),
});
return useQuery({
queryKey: userQueryKeys.list(),
queryFn: ({ signal }) => getUsers(signal),
});
}
export function useCustomers() {
return useQuery({
queryKey: userQueryKeys.customers(),
queryFn: ({signal}) => getCustomers(signal),
});
return useQuery({
queryKey: userQueryKeys.customers(),
queryFn: ({ signal }) => getCustomers(signal),
});
}
export function useDrivers() {
return useQuery({
queryKey: userQueryKeys.drivers(),
queryFn: ({signal}) => getDrivers(signal),
});
return useQuery({
queryKey: userQueryKeys.drivers(),
queryFn: ({ signal }) => getDrivers(signal),
});
}
export function useCreateUser() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: createUser,
onSuccess: () => queryClient.invalidateQueries({queryKey: userQueryKeys.all}),
});
return useMutation({
mutationFn: createUser,
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: userQueryKeys.all }),
});
}
export function useUpdateUser() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({id, request}: {id: string; request: AdminUserRequest}) => updateUser(id, request),
onSuccess: () => queryClient.invalidateQueries({queryKey: userQueryKeys.all}),
});
return useMutation({
mutationFn: ({ id, request }: { id: string; request: AdminUserRequest }) =>
updateUser(id, request),
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: userQueryKeys.all }),
});
}
export function useDisableUser() {
const queryClient = useQueryClient();
const queryClient = useQueryClient();
return useMutation({
mutationFn: disableUser,
onSuccess: () => queryClient.invalidateQueries({queryKey: userQueryKeys.all}),
});
return useMutation({
mutationFn: disableUser,
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: userQueryKeys.all }),
});
}