task-fic-display

This commit is contained in:
phaichayon
2026-06-27 22:14:16 +07:00
parent 1c019d12f3
commit 071293b60f
30 changed files with 2329 additions and 107 deletions

View File

@@ -1 +1,59 @@
export {};
import { mutationOptions } from '@tanstack/react-query';
import { getQueryClient } from '@/lib/query-client';
import {
createMasterOption,
deleteMasterOption,
updateMasterOption
} from './service';
import { masterOptionKeys } from './queries';
import type { MasterOptionMutationPayload } from './types';
async function invalidateMasterOptionLists() {
const queryClient = getQueryClient();
await Promise.all([
queryClient.invalidateQueries({ queryKey: masterOptionKeys.lists() }),
queryClient.invalidateQueries({ queryKey: masterOptionKeys.categories() })
]);
}
async function invalidateMasterOptionDetail(id: string) {
await getQueryClient().invalidateQueries({ queryKey: masterOptionKeys.detail(id) });
}
export const createMasterOptionMutation = mutationOptions({
mutationFn: (data: MasterOptionMutationPayload) => createMasterOption(data),
onSettled: async (_data, error) => {
if (!error) {
await invalidateMasterOptionLists();
}
}
});
export const updateMasterOptionMutation = mutationOptions({
mutationFn: ({
id,
values
}: {
id: string;
values: Partial<MasterOptionMutationPayload>;
}) => updateMasterOption(id, values),
onSettled: async (_data, error, variables) => {
if (!error) {
await Promise.all([
invalidateMasterOptionLists(),
invalidateMasterOptionDetail(variables.id)
]);
}
}
});
export const deleteMasterOptionMutation = mutationOptions({
mutationFn: (id: string) => deleteMasterOption(id),
onSettled: async (_data, error, id) => {
if (!error) {
const queryClient = getQueryClient();
await invalidateMasterOptionLists();
queryClient.removeQueries({ queryKey: masterOptionKeys.detail(id) });
}
}
});

View File

@@ -1,10 +1,18 @@
import { queryOptions } from '@tanstack/react-query';
import { getMasterOptions } from './service';
import {
getMasterOptionById,
getMasterOptionCategories,
getMasterOptions
} from './service';
import type { MasterOptionsFilters } from './types';
export const masterOptionKeys = {
all: ['foundation', 'master-options'] as const,
list: (filters: MasterOptionsFilters) => [...masterOptionKeys.all, 'list', filters] as const
all: ['foundation', 'ms-options'] as const,
lists: () => [...masterOptionKeys.all, 'list'] as const,
list: (filters: MasterOptionsFilters) => [...masterOptionKeys.lists(), filters] as const,
details: () => [...masterOptionKeys.all, 'detail'] as const,
detail: (id: string) => [...masterOptionKeys.details(), id] as const,
categories: () => [...masterOptionKeys.all, 'categories'] as const
};
export const masterOptionsQueryOptions = (filters: MasterOptionsFilters) =>
@@ -12,3 +20,15 @@ export const masterOptionsQueryOptions = (filters: MasterOptionsFilters) =>
queryKey: masterOptionKeys.list(filters),
queryFn: () => getMasterOptions(filters)
});
export const masterOptionByIdQueryOptions = (id: string) =>
queryOptions({
queryKey: masterOptionKeys.detail(id),
queryFn: () => getMasterOptionById(id)
});
export const masterOptionCategoriesQueryOptions = () =>
queryOptions({
queryKey: masterOptionKeys.categories(),
queryFn: () => getMasterOptionCategories()
});

View File

@@ -1,9 +1,16 @@
import { apiClient } from '@/lib/api-client';
import type { MasterOptionsFilters, MasterOptionsResponse } from './types';
import type {
MasterOptionCategoriesResponse,
MasterOptionDetailResponse,
MasterOptionMutationPayload,
MasterOptionsFilters,
MasterOptionsResponse,
MutationSuccessResponse
} from './types';
export async function getMasterOptions(
filters: MasterOptionsFilters
): Promise<MasterOptionsResponse> {
const BASE_PATH = '/foundation/ms-options';
export async function getMasterOptions(filters: MasterOptionsFilters): Promise<MasterOptionsResponse> {
const searchParams = new URLSearchParams();
if (filters.page) searchParams.set('page', String(filters.page));
@@ -13,6 +20,38 @@ export async function getMasterOptions(
if (filters.sort) searchParams.set('sort', filters.sort);
const query = searchParams.toString();
return apiClient<MasterOptionsResponse>(`/foundation/master-options${query ? `?${query}` : ''}`);
return apiClient<MasterOptionsResponse>(`${BASE_PATH}${query ? `?${query}` : ''}`);
}
export async function getMasterOptionById(id: string): Promise<MasterOptionDetailResponse> {
return apiClient<MasterOptionDetailResponse>(`${BASE_PATH}/${id}`);
}
export async function createMasterOption(
data: MasterOptionMutationPayload
): Promise<MutationSuccessResponse> {
return apiClient<MutationSuccessResponse>(BASE_PATH, {
method: 'POST',
body: JSON.stringify(data)
});
}
export async function updateMasterOption(
id: string,
data: Partial<MasterOptionMutationPayload>
): Promise<MutationSuccessResponse> {
return apiClient<MutationSuccessResponse>(`${BASE_PATH}/${id}`, {
method: 'PATCH',
body: JSON.stringify(data)
});
}
export async function deleteMasterOption(id: string): Promise<MutationSuccessResponse> {
return apiClient<MutationSuccessResponse>(`${BASE_PATH}/${id}`, {
method: 'DELETE'
});
}
export async function getMasterOptionCategories(): Promise<MasterOptionCategoriesResponse> {
return apiClient<MasterOptionCategoriesResponse>(`${BASE_PATH}/categories`);
}

View File

@@ -9,7 +9,9 @@ export interface MasterOptionItem {
parent_label: string | null;
sort_order: number;
is_active: boolean;
metadata: Record<string, unknown> | null;
deleted_at: string | null;
created_at: string;
updated_at: string;
}
@@ -21,6 +23,17 @@ export interface MasterOptionsFilters {
sort?: string;
}
export interface MasterOptionMutationPayload {
category: string;
code: string;
label: string;
value?: string | null;
parent_id?: string | null;
sort_order?: number;
is_active?: boolean;
metadata?: Record<string, unknown> | null;
}
export interface MasterOptionsResponse {
success: boolean;
time: string;
@@ -30,3 +43,26 @@ export interface MasterOptionsResponse {
limit: number;
items: MasterOptionItem[];
}
export interface MasterOptionDetailResponse {
success: boolean;
time: string;
message: string;
item: MasterOptionItem;
}
export interface MasterOptionCategoriesResponse {
success: boolean;
time: string;
message: string;
items: Array<{
category: string;
total_items: number;
active_items: number;
}>;
}
export interface MutationSuccessResponse {
success: boolean;
message: string;
}