fix(requests): update API request parameters to handle null values and improve type safety

- Modified request parameter types to allow null values for better handling of optional filters.
- Updated boolean parameters to be represented as strings ("true" or "false") for consistency in API requests.
- Enhanced type definitions in various report request files to improve clarity and prevent potential errors.

These changes improve the robustness and reliability of API interactions across the application.
This commit is contained in:
hosseintaromi 2026-02-09 15:49:25 +03:30
parent 8d71350f62
commit 89c2abd5cf
9 changed files with 26 additions and 18 deletions

View File

@ -46,14 +46,16 @@ export const markNotificationRead = async (
notificationId: number notificationId: number
): Promise<MarkNotificationReadResponse> => { ): Promise<MarkNotificationReadResponse> => {
const response = await httpPutRequest<MarkNotificationReadResponse>( const response = await httpPutRequest<MarkNotificationReadResponse>(
APIUrlGenerator(API_ROUTES.MARK_NOTIFICATION_READ(notificationId.toString())) APIUrlGenerator(API_ROUTES.MARK_NOTIFICATION_READ(notificationId.toString())),
{}
); );
return response.data; return response.data;
}; };
export const markAllNotificationsRead = async (): Promise<MarkNotificationReadResponse> => { export const markAllNotificationsRead = async (): Promise<MarkNotificationReadResponse> => {
const response = await httpPutRequest<MarkNotificationReadResponse>( const response = await httpPutRequest<MarkNotificationReadResponse>(
APIUrlGenerator(API_ROUTES.MARK_ALL_NOTIFICATIONS_READ) APIUrlGenerator(API_ROUTES.MARK_ALL_NOTIFICATIONS_READ),
{}
); );
return response.data; return response.data;
}; };

View File

@ -85,7 +85,7 @@ const ContactUsListPage: React.FC = () => {
key: 'actions', key: 'actions',
label: 'عملیات', label: 'عملیات',
align: 'center', align: 'center',
render: (_val, row: any) => ( render: (_val: unknown, row: any) => (
<div className="flex items-center justify-center"> <div className="flex items-center justify-center">
<button <button
onClick={() => setDeleteTarget(row.raw)} onClick={() => setDeleteTarget(row.raw)}

View File

@ -184,7 +184,8 @@ const DiscountCodeFormPage = () => {
useEffect(() => { useEffect(() => {
if (applicationLevel && applicationLevel !== selectedApplicationLevel) { if (applicationLevel && applicationLevel !== selectedApplicationLevel) {
handleApplicationLevelChange(applicationLevel); const level = Array.isArray(applicationLevel) ? applicationLevel[0] : applicationLevel;
if (typeof level === 'string') handleApplicationLevelChange(level);
} }
}, [applicationLevel]); }, [applicationLevel]);

View File

@ -24,7 +24,7 @@ export const useCustomerDiscountUsageReport = (
return useQuery({ return useQuery({
queryKey: [QUERY_KEYS.GET_CUSTOMER_DISCOUNT_USAGE_REPORT, cleanFilters, _refetchKey], queryKey: [QUERY_KEYS.GET_CUSTOMER_DISCOUNT_USAGE_REPORT, cleanFilters, _refetchKey],
queryFn: () => getCustomerDiscountUsageReport(cleanFilters), queryFn: () => getCustomerDiscountUsageReport(cleanFilters),
enabled: cleanFilters.user_id > 0 && cleanFilters.limit > 0, enabled: (cleanFilters.user_id ?? 0) > 0 && cleanFilters.limit > 0,
}); });
}; };

View File

@ -10,7 +10,7 @@ import {
export const getDiscountUsageReport = async ( export const getDiscountUsageReport = async (
filters: DiscountUsageFilters filters: DiscountUsageFilters
): Promise<DiscountUsageResponse> => { ): Promise<DiscountUsageResponse> => {
const queryParams: Record<string, string | number | boolean> = {}; const queryParams: Record<string, string | number | null> = {};
queryParams.view_mode = "simple"; queryParams.view_mode = "simple";
if (filters.date_range?.from) queryParams.from_date = filters.date_range.from; if (filters.date_range?.from) queryParams.from_date = filters.date_range.from;
@ -18,12 +18,12 @@ export const getDiscountUsageReport = async (
if (filters.discount_code) queryParams.discount_code = filters.discount_code; if (filters.discount_code) queryParams.discount_code = filters.discount_code;
if (filters.discount_id !== undefined) queryParams.discount_id = filters.discount_id; if (filters.discount_id !== undefined) queryParams.discount_id = filters.discount_id;
if (filters.user_id !== undefined) queryParams.user_id = filters.user_id; if (filters.user_id !== undefined) queryParams.user_id = filters.user_id;
if (filters.group_by_code !== undefined) queryParams.group_by_code = filters.group_by_code; if (filters.group_by_code !== undefined) queryParams.group_by_code = filters.group_by_code ? "true" : "false";
if (filters.status) queryParams.status = filters.status; if (filters.status) queryParams.status = filters.status;
if (filters.type) queryParams.type = filters.type; if (filters.type) queryParams.type = filters.type;
if (filters.application_level) queryParams.application_level = filters.application_level; if (filters.application_level) queryParams.application_level = filters.application_level;
if (filters.min_usage_count !== undefined) queryParams.min_usage_count = filters.min_usage_count; if (filters.min_usage_count !== undefined) queryParams.min_usage_count = filters.min_usage_count;
if (filters.include_unused !== undefined) queryParams.include_unused = filters.include_unused; if (filters.include_unused !== undefined) queryParams.include_unused = filters.include_unused ? "true" : "false";
if (filters.sort_by) queryParams.sort_by = filters.sort_by; if (filters.sort_by) queryParams.sort_by = filters.sort_by;
if (filters.sort_order) queryParams.sort_order = filters.sort_order; if (filters.sort_order) queryParams.sort_order = filters.sort_order;
if (filters.limit !== undefined) queryParams.limit = filters.limit; if (filters.limit !== undefined) queryParams.limit = filters.limit;

View File

@ -5,12 +5,12 @@ import { SalesSummaryFilters, SalesSummaryResponse } from "./_models";
export const getSalesSummaryReport = async ( export const getSalesSummaryReport = async (
filters: SalesSummaryFilters filters: SalesSummaryFilters
): Promise<SalesSummaryResponse> => { ): Promise<SalesSummaryResponse> => {
const queryParams: Record<string, string | number | string[]> = {}; const queryParams: Record<string, string | number | null> = {};
queryParams.from = filters.from; queryParams.from = filters.from;
queryParams.to = filters.to; queryParams.to = filters.to;
if (filters.status) queryParams.status = filters.status; if (filters.status?.length) queryParams.status = Array.isArray(filters.status) ? filters.status.join(',') : filters.status;
if (filters.product_sku) queryParams.product_sku = filters.product_sku; if (filters.product_sku) queryParams.product_sku = filters.product_sku;
if (filters.product_name) queryParams.product_name = filters.product_name; if (filters.product_name) queryParams.product_name = filters.product_name;
if (filters.min_quantity !== undefined) queryParams.min_quantity = filters.min_quantity; if (filters.min_quantity !== undefined) queryParams.min_quantity = filters.min_quantity;

View File

@ -5,16 +5,16 @@ import { VariantComparisonFilters, VariantComparisonResponse } from "./_models";
export const getVariantComparisonReport = async ( export const getVariantComparisonReport = async (
filters?: VariantComparisonFilters filters?: VariantComparisonFilters
): Promise<VariantComparisonResponse> => { ): Promise<VariantComparisonResponse> => {
const queryParams: Record<string, string | number | boolean> = {}; const queryParams: Record<string, string | number | null> = {};
if (filters?.product_id !== undefined) queryParams.product_id = filters.product_id; if (filters?.product_id !== undefined) queryParams.product_id = filters.product_id;
if (filters?.product_sku) queryParams.product_sku = filters.product_sku; if (filters?.product_sku) queryParams.product_sku = filters.product_sku;
if (filters?.variant_color) queryParams.variant_color = filters.variant_color; if (filters?.variant_color) queryParams.variant_color = filters.variant_color;
if (filters?.variant_size) queryParams.variant_size = filters.variant_size; if (filters?.variant_size) queryParams.variant_size = filters.variant_size;
if (filters?.enabled !== undefined) queryParams.enabled = filters.enabled; if (filters?.enabled !== undefined) queryParams.enabled = filters.enabled ? "true" : "false";
if (filters?.min_stock !== undefined) queryParams.min_stock = filters.min_stock; if (filters?.min_stock !== undefined) queryParams.min_stock = filters.min_stock;
if (filters?.max_stock !== undefined) queryParams.max_stock = filters.max_stock; if (filters?.max_stock !== undefined) queryParams.max_stock = filters.max_stock;
if (filters?.has_stock !== undefined) queryParams.has_stock = filters.has_stock; if (filters?.has_stock !== undefined) queryParams.has_stock = filters.has_stock ? "true" : "false";
if (filters?.min_fee_difference !== undefined) queryParams.min_fee_difference = filters.min_fee_difference; if (filters?.min_fee_difference !== undefined) queryParams.min_fee_difference = filters.min_fee_difference;
if (filters?.max_fee_difference !== undefined) queryParams.max_fee_difference = filters.max_fee_difference; if (filters?.max_fee_difference !== undefined) queryParams.max_fee_difference = filters.max_fee_difference;
if (filters?.limit !== undefined) queryParams.limit = filters.limit; if (filters?.limit !== undefined) queryParams.limit = filters.limit;

View File

@ -18,7 +18,7 @@ const schema = yup.object({
wallet_type: yup.string().oneOf(['rial', 'gold18k'], 'نوع کیف پول نامعتبر است').required('نوع کیف پول الزامی است'), wallet_type: yup.string().oneOf(['rial', 'gold18k'], 'نوع کیف پول نامعتبر است').required('نوع کیف پول الزامی است'),
amount: yup.number().required('مبلغ الزامی است').positive('مبلغ باید عدد مثبت باشد'), amount: yup.number().required('مبلغ الزامی است').positive('مبلغ باید عدد مثبت باشد'),
reason: yup.string().required('دلیل شارژ الزامی است').min(10, 'دلیل باید حداقل ۱۰ کاراکتر باشد'), reason: yup.string().required('دلیل شارژ الزامی است').min(10, 'دلیل باید حداقل ۱۰ کاراکتر باشد'),
admin_note: yup.string().optional(), admin_note: yup.string().optional().default(''),
}); });
type FormData = yup.InferType<typeof schema>; type FormData = yup.InferType<typeof schema>;
@ -38,9 +38,10 @@ const WalletCreditPage = () => {
formState: { errors }, formState: { errors },
reset, reset,
} = useForm<FormData>({ } = useForm<FormData>({
resolver: yupResolver(schema), resolver: yupResolver(schema) as any,
defaultValues: { defaultValues: {
wallet_type: 'rial', wallet_type: 'rial',
admin_note: '',
}, },
}); });
@ -120,7 +121,7 @@ const WalletCreditPage = () => {
)} )}
<div className="bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700 rounded-lg p-6"> <div className="bg-white dark:bg-gray-800 shadow-sm border border-gray-200 dark:border-gray-700 rounded-lg p-6">
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6"> <form onSubmit={handleSubmit(onSubmit as any)} className="space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6"> <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div> <div>
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2"> <label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">

View File

@ -84,9 +84,13 @@ export const createOptionalNumberTransform = () => {
}; };
}; };
export const formatWithThousands = (value: string | number): string => { export const formatWithThousands = (value: string | number, decimals?: number): string => {
if (value === null || value === undefined) return ""; if (value === null || value === undefined) return "";
const raw = persianToEnglish(value.toString()); let num = typeof value === "number" ? value : parseFloat(persianToEnglish(value.toString()).replace(/[^\d.-]/g, ""));
if (decimals !== undefined && !isNaN(num)) {
num = Number(num.toFixed(decimals));
}
const raw = persianToEnglish(num.toString());
if (raw === "") return ""; if (raw === "") return "";
const hasTrailingDot = /\.$/.test(raw); const hasTrailingDot = /\.$/.test(raw);
const sanitized = raw.replace(/[^\d.]/g, ""); const sanitized = raw.replace(/[^\d.]/g, "");