фильтры

This commit is contained in:
2025-07-27 07:39:01 +03:00
parent f5b2a5e6ee
commit bfaba2723c
5 changed files with 736 additions and 77 deletions

View File

@@ -9,7 +9,7 @@ export interface CreateTemplateOutput {
}
export interface GetTemplatesOutput {
templates: ApiTemplate[]
templates: ApiTemplateWithAttributes[]
}
export interface GetTemplateOutput {
@@ -24,6 +24,10 @@ export interface PatchTemplateInput {
name?: string | null
description?: string | null
elements?: Record<string, any> | null
attributes?: Array<{
attribute_id: string
value: string | null
}> | null
}
export interface PatchTemplateOutput {
@@ -126,6 +130,7 @@ export function templateToPatchInput(template: Template): PatchTemplateInput {
name: template.name,
description: template.description,
elements,
// attributes будут добавлены отдельно в TemplateContext при необходимости
}
}
@@ -178,7 +183,7 @@ export async function getTemplatesApi(): Promise<GetTemplatesOutput> {
// API получение конкретного шаблона
export async function getTemplateApi(
templateId: UUID
templateId: string
): Promise<GetTemplateOutput> {
try {
const response = await fetch(`/api/templates/${templateId}`, {
@@ -202,18 +207,15 @@ export async function getTemplateApi(
// API получение шаблона с атрибутами
export async function getTemplateWithAttributesApi(
templateId: UUID
templateId: string
): Promise<GetTemplateWithAttributesOutput> {
try {
const response = await fetch(
`/api/templates/${templateId}/with-attributes`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
}
)
const response = await fetch(`/api/templates/${templateId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
@@ -260,3 +262,73 @@ export async function updateTemplate(
const patchInput = templateToPatchInput(template)
return patchTemplateApi(template.id, patchInput)
}
// Интерфейсы для копирования шаблона
export interface CopyTemplateInput {
template_id: string
new_name: string
new_description?: string | null
new_attributes?: Array<{
attribute_id: string
value: string | null
}> | null
}
export interface CopyTemplateOutput {
new_template_id: string
}
// Интерфейсы для удаления шаблона
export interface DeleteTemplateOutput {
success: boolean
template_id: string
}
// API копирование шаблона
export async function copyTemplateApi(
input: CopyTemplateInput
): Promise<CopyTemplateOutput> {
try {
const response = await fetch('/api/templates/copy', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const result: CopyTemplateOutput = await response.json()
return result
} catch (error) {
console.error('Ошибка при копировании шаблона:', error)
throw new Error('Ошибка при копировании шаблона на сервере')
}
}
// API удаление шаблона
export async function deleteTemplateApi(
templateId: string
): Promise<DeleteTemplateOutput> {
try {
const response = await fetch(`/api/templates/${templateId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const result: DeleteTemplateOutput = await response.json()
return result
} catch (error) {
console.error('Ошибка при удалении шаблона:', error)
throw new Error('Ошибка при удалении шаблона на сервере')
}
}

View File

@@ -1,6 +1,10 @@
import {
apiTemplateToTemplate,
apiTemplateWithAttributesToTemplate,
copyTemplateApi,
CopyTemplateInput,
createTemplateApi,
deleteTemplateApi,
getTemplateApi,
getTemplatesApi,
patchTemplateApi,
@@ -26,8 +30,17 @@ interface TemplateContextType {
addTemplate: (
data: Omit<Template, 'id' | 'createdAt' | 'updatedAt'>
) => Promise<Template>
updateTemplate: (template: Template) => Promise<Template>
deleteTemplate: (id: UUID) => Promise<string>
updateTemplate: (
template: Template,
attributes?: Array<{ attributeId: string; value: string | null }>
) => Promise<Template>
deleteTemplate: (id: string) => Promise<string>
copyTemplate: (
templateId: string,
newName: string,
newDescription?: string,
attributes?: Array<{ attributeId: string; value: string | null }>
) => Promise<Template>
}
const TemplateContext = createContext<TemplateContextType | undefined>(
@@ -48,7 +61,7 @@ export const TemplateProvider: React.FC<{ children: ReactNode }> = ({
queryKey: ['templates'],
queryFn: async () => {
const { templates: apiList } = await getTemplatesApi()
return apiList.map(apiTemplateToTemplate)
return apiList.map(apiTemplateWithAttributesToTemplate)
},
})
@@ -68,8 +81,20 @@ export const TemplateProvider: React.FC<{ children: ReactNode }> = ({
})
const updateMutation = useMutation({
mutationFn: async (template: Template) => {
mutationFn: async ({
template,
attributes,
}: {
template: Template
attributes?: Array<{ attributeId: string; value: string | null }>
}) => {
const input = templateToPatchInput(template)
if (attributes) {
input.attributes = attributes.map(attr => ({
attribute_id: attr.attributeId,
value: attr.value,
}))
}
await patchTemplateApi(template.id, input)
return template
},
@@ -84,7 +109,10 @@ export const TemplateProvider: React.FC<{ children: ReactNode }> = ({
const deleteMutation = useMutation({
mutationFn: async (id: string) => {
// TODO: deleteTemplateApi
const result = await deleteTemplateApi(id)
if (!result.success) {
throw new Error('Не удалось удалить шаблон')
}
return id
},
onSuccess: id => {
@@ -95,6 +123,38 @@ export const TemplateProvider: React.FC<{ children: ReactNode }> = ({
},
})
const copyMutation = useMutation({
mutationFn: async ({
templateId,
newName,
newDescription,
attributes,
}: {
templateId: string
newName: string
newDescription?: string
attributes?: Array<{ attributeId: string; value: string | null }>
}) => {
const input: CopyTemplateInput = {
template_id: templateId,
new_name: newName,
new_description: newDescription || null,
new_attributes:
attributes?.map(attr => ({
attribute_id: attr.attributeId,
value: attr.value,
})) || null,
}
const { new_template_id } = await copyTemplateApi(input)
const { template: apiTpl } = await getTemplateApi(new_template_id)
if (!apiTpl) throw new Error('Copied template not found')
return apiTemplateToTemplate(apiTpl)
},
onSuccess: () => {
client.invalidateQueries({ queryKey: ['templates'] })
},
})
const value = useMemo(
() => ({
templates,
@@ -102,17 +162,38 @@ export const TemplateProvider: React.FC<{ children: ReactNode }> = ({
listStatus === 'pending' ||
createMutation.status === 'pending' ||
updateMutation.status === 'pending' ||
deleteMutation.status === 'pending',
deleteMutation.status === 'pending' ||
copyMutation.status === 'pending',
error:
(errorList as Error) ||
(createMutation.error as Error) ||
(updateMutation.error as Error) ||
(deleteMutation.error as Error) ||
(copyMutation.error as Error) ||
null,
refetchTemplates: refetch,
addTemplate: createMutation.mutateAsync,
updateTemplate: updateMutation.mutateAsync,
updateTemplate: async (
template: Template,
attributes?: Array<{ attributeId: string; value: string | null }>
) =>
updateMutation.mutateAsync({
template,
attributes,
}),
deleteTemplate: deleteMutation.mutateAsync,
copyTemplate: async (
templateId: string,
newName: string,
newDescription?: string,
attributes?: Array<{ attributeId: string; value: string | null }>
) =>
copyMutation.mutateAsync({
templateId,
newName,
newDescription,
attributes,
}),
}),
[
templates,
@@ -124,10 +205,13 @@ export const TemplateProvider: React.FC<{ children: ReactNode }> = ({
updateMutation.error,
deleteMutation.status,
deleteMutation.error,
copyMutation.status,
copyMutation.error,
refetch,
createMutation.mutateAsync,
updateMutation.mutateAsync,
deleteMutation.mutateAsync,
copyMutation.mutateAsync,
]
)