refactor(api): streamline customer, order, service, and slot actions by wrapping server functions with client action utility to rethrow error messages to client

This commit is contained in:
vchikalkin 2025-07-23 13:13:07 +03:00
parent 57cab6209d
commit f1da2c834a
9 changed files with 180 additions and 124 deletions

View File

@ -1,36 +1,8 @@
'use server'; import * as customers from './server/customers';
import { wrapClientAction } from '@/utils/actions';
import { useService } from './lib/service'; export const addMasters = wrapClientAction(customers.addMasters);
import { CustomersService } from '@repo/graphql/api/customers'; export const getClients = wrapClientAction(customers.getClients);
export const getCustomer = wrapClientAction(customers.getCustomer);
const getService = useService(CustomersService); export const getMasters = wrapClientAction(customers.getMasters);
export const updateCustomer = wrapClientAction(customers.updateCustomer);
export async function addMasters(...variables: Parameters<CustomersService['addMasters']>) {
const service = await getService();
return service.addMasters(...variables);
}
export async function getClients(...variables: Parameters<CustomersService['getClients']>) {
const service = await getService();
return service.getClients(...variables);
}
export async function getCustomer(...variables: Parameters<CustomersService['getCustomer']>) {
const service = await getService();
return service.getCustomer(...variables);
}
export async function getMasters(...variables: Parameters<CustomersService['getMasters']>) {
const service = await getService();
return service.getMasters(...variables);
}
export async function updateCustomer(...variables: Parameters<CustomersService['updateCustomer']>) {
const service = await getService();
return service.updateCustomer(...variables);
}

View File

@ -1,30 +1,7 @@
'use server'; import * as orders from './server/orders';
import { wrapClientAction } from '@/utils/actions';
import { useService } from './lib/service'; export const createOrder = wrapClientAction(orders.createOrder);
import { OrdersService } from '@repo/graphql/api/orders'; export const getOrder = wrapClientAction(orders.getOrder);
export const getOrders = wrapClientAction(orders.getOrders);
const getServicesService = useService(OrdersService); export const updateOrder = wrapClientAction(orders.updateOrder);
export async function createOrder(...variables: Parameters<OrdersService['createOrder']>) {
const service = await getServicesService();
return service.createOrder(...variables);
}
export async function getOrder(...variables: Parameters<OrdersService['getOrder']>) {
const service = await getServicesService();
return service.getOrder(...variables);
}
export async function getOrders(...variables: Parameters<OrdersService['getOrders']>) {
const service = await getServicesService();
return service.getOrders(...variables);
}
export async function updateOrder(...variables: Parameters<OrdersService['updateOrder']>) {
const service = await getServicesService();
return service.updateOrder(...variables);
}

View File

@ -0,0 +1,37 @@
'use server';
import { useService } from '../lib/service';
import { wrapServerAction } from '@/utils/actions';
import { CustomersService } from '@repo/graphql/api/customers';
const getService = useService(CustomersService);
export async function addMasters(...variables: Parameters<CustomersService['addMasters']>) {
const service = await getService();
return wrapServerAction(() => service.addMasters(...variables));
}
export async function getClients(...variables: Parameters<CustomersService['getClients']>) {
const service = await getService();
return wrapServerAction(() => service.getClients(...variables));
}
export async function getCustomer(...variables: Parameters<CustomersService['getCustomer']>) {
const service = await getService();
return wrapServerAction(() => service.getCustomer(...variables));
}
export async function getMasters(...variables: Parameters<CustomersService['getMasters']>) {
const service = await getService();
return wrapServerAction(() => service.getMasters(...variables));
}
export async function updateCustomer(...variables: Parameters<CustomersService['updateCustomer']>) {
const service = await getService();
return wrapServerAction(() => service.updateCustomer(...variables));
}

View File

@ -0,0 +1,31 @@
'use server';
import { useService } from '../lib/service';
import { wrapServerAction } from '@/utils/actions';
import { OrdersService } from '@repo/graphql/api/orders';
const getServicesService = useService(OrdersService);
export async function createOrder(...variables: Parameters<OrdersService['createOrder']>) {
const service = await getServicesService();
return wrapServerAction(() => service.createOrder(...variables));
}
export async function getOrder(...variables: Parameters<OrdersService['getOrder']>) {
const service = await getServicesService();
return wrapServerAction(() => service.getOrder(...variables));
}
export async function getOrders(...variables: Parameters<OrdersService['getOrders']>) {
const service = await getServicesService();
return wrapServerAction(() => service.getOrders(...variables));
}
export async function updateOrder(...variables: Parameters<OrdersService['updateOrder']>) {
const service = await getServicesService();
return wrapServerAction(() => service.updateOrder(...variables));
}

View File

@ -0,0 +1,19 @@
'use server';
import { useService } from '../lib/service';
import { wrapServerAction } from '@/utils/actions';
import { ServicesService } from '@repo/graphql/api/services';
const getServicesService = useService(ServicesService);
export async function getService(...variables: Parameters<ServicesService['getService']>) {
const service = await getServicesService();
return wrapServerAction(() => service.getService(...variables));
}
export async function getServices(...variables: Parameters<ServicesService['getServices']>) {
const service = await getServicesService();
return wrapServerAction(() => service.getServices(...variables));
}

View File

@ -0,0 +1,45 @@
'use server';
import { useService } from '../lib/service';
import { wrapServerAction } from '@/utils/actions';
import { SlotsService } from '@repo/graphql/api/slots';
const getService = useService(SlotsService);
export async function createSlot(...variables: Parameters<SlotsService['createSlot']>) {
const service = await getService();
return wrapServerAction(() => service.createSlot(...variables));
}
export async function deleteSlot(...variables: Parameters<SlotsService['deleteSlot']>) {
const service = await getService();
return wrapServerAction(() => service.deleteSlot(...variables));
}
export async function getAvailableTimeSlots(
...variables: Parameters<SlotsService['getAvailableTimeSlots']>
) {
const service = await getService();
return wrapServerAction(() => service.getAvailableTimeSlots(...variables));
}
export async function getSlot(...variables: Parameters<SlotsService['getSlot']>) {
const service = await getService();
return wrapServerAction(() => service.getSlot(...variables));
}
export async function getSlots(...variables: Parameters<SlotsService['getSlots']>) {
const service = await getService();
return wrapServerAction(() => service.getSlots(...variables));
}
export async function updateSlot(...variables: Parameters<SlotsService['updateSlot']>) {
const service = await getService();
return wrapServerAction(() => service.updateSlot(...variables));
}

View File

@ -1,18 +1,5 @@
'use server'; import * as services from './server/services';
import { wrapClientAction } from '@/utils/actions';
import { useService } from './lib/service'; export const getServices = wrapClientAction(services.getServices);
import { ServicesService } from '@repo/graphql/api/services'; export const getService = wrapClientAction(services.getService);
const getServicesService = useService(ServicesService);
export async function getService(...variables: Parameters<ServicesService['getService']>) {
const service = await getServicesService();
return service.getService(...variables);
}
export async function getServices(...variables: Parameters<ServicesService['getServices']>) {
const service = await getServicesService();
return service.getServices(...variables);
}

View File

@ -1,44 +1,9 @@
'use server'; import * as slots from './server/slots';
import { wrapClientAction } from '@/utils/actions';
import { useService } from './lib/service'; export const getSlot = wrapClientAction(slots.getSlot);
import { SlotsService } from '@repo/graphql/api/slots'; export const getSlots = wrapClientAction(slots.getSlots);
export const createSlot = wrapClientAction(slots.createSlot);
const getService = useService(SlotsService); export const updateSlot = wrapClientAction(slots.updateSlot);
export const deleteSlot = wrapClientAction(slots.deleteSlot);
export async function createSlot(...variables: Parameters<SlotsService['createSlot']>) { export const getAvailableTimeSlots = wrapClientAction(slots.getAvailableTimeSlots);
const service = await getService();
return service.createSlot(...variables);
}
export async function deleteSlot(...variables: Parameters<SlotsService['deleteSlot']>) {
const service = await getService();
return service.deleteSlot(...variables);
}
export async function getAvailableTimeSlots(
...variables: Parameters<SlotsService['getAvailableTimeSlots']>
) {
const service = await getService();
return service.getAvailableTimeSlots(...variables);
}
export async function getSlot(...variables: Parameters<SlotsService['getSlot']>) {
const service = await getService();
return service.getSlot(...variables);
}
export async function getSlots(...variables: Parameters<SlotsService['getSlots']>) {
const service = await getService();
return service.getSlots(...variables);
}
export async function updateSlot(...variables: Parameters<SlotsService['updateSlot']>) {
const service = await getService();
return service.updateSlot(...variables);
}

23
apps/web/utils/actions.ts Normal file
View File

@ -0,0 +1,23 @@
/* eslint-disable unicorn/prevent-abbreviations */
export function wrapClientAction<Args extends unknown[], Return>(
fn: (...args: Args) => Promise<{ data?: Return; error?: string; ok: boolean }>,
): (...args: Args) => Promise<Return> {
return async (...args: Args): Promise<Return> => {
const res = await fn(...args);
if (!res.ok) throw new Error(res.error ?? 'Неизвестная ошибка');
return res.data as Return;
};
}
export async function wrapServerAction<T>(
action: () => Promise<T>,
): Promise<{ data: T; ok: true } | { error: string; ok: false }> {
try {
const data = await action();
return { data, ok: true };
} catch (error) {
const message = error instanceof Error ? error.message : 'Неизвестная ошибка сервера';
return { error: message, ok: false };
}
}