Files
protoc-frontend/src/entitiy/template/model/TemplateContext.tsx
2025-07-27 07:39:01 +03:00

233 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
apiTemplateToTemplate,
apiTemplateWithAttributesToTemplate,
copyTemplateApi,
CopyTemplateInput,
createTemplateApi,
deleteTemplateApi,
getTemplateApi,
getTemplatesApi,
patchTemplateApi,
templateToCreateInput,
templateToPatchInput,
} from '@/entitiy/template/api/templateApiService'
import { Template } from '@/type/template'
import {
QueryClient,
useMutation,
useQuery,
useQueryClient,
} from '@tanstack/react-query'
import React, { createContext, ReactNode, useContext, useMemo } from 'react'
export const queryClient = new QueryClient()
interface TemplateContextType {
templates: Template[]
isLoading: boolean
error: Error | null
refetchTemplates: () => void
addTemplate: (
data: Omit<Template, 'id' | 'createdAt' | 'updatedAt'>
) => Promise<Template>
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>(
undefined
)
export const TemplateProvider: React.FC<{ children: ReactNode }> = ({
children,
}) => {
const client = useQueryClient()
const {
data: templates = [],
status: listStatus,
error: errorList,
refetch,
} = useQuery<Template[], Error>({
queryKey: ['templates'],
queryFn: async () => {
const { templates: apiList } = await getTemplatesApi()
return apiList.map(apiTemplateWithAttributesToTemplate)
},
})
const createMutation = useMutation({
mutationFn: async (
newTemplate: Omit<Template, 'id' | 'createdAt' | 'updatedAt'>
) => {
const input = templateToCreateInput(newTemplate)
const { id } = await createTemplateApi(input)
const { template: apiTpl } = await getTemplateApi(id)
if (!apiTpl) throw new Error('Template not found')
return apiTemplateToTemplate(apiTpl)
},
onSuccess: () => {
client.invalidateQueries({ queryKey: ['templates'] })
},
})
const updateMutation = useMutation({
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
},
onSuccess: updated => {
client.setQueryData<Template[]>(
['templates'],
old =>
old?.map((t: Template) => (t.id === updated.id ? updated : t)) ?? []
)
},
})
const deleteMutation = useMutation({
mutationFn: async (id: string) => {
const result = await deleteTemplateApi(id)
if (!result.success) {
throw new Error('Не удалось удалить шаблон')
}
return id
},
onSuccess: id => {
client.setQueryData<Template[]>(
['templates'],
old => old?.filter((t: Template) => t.id !== id) ?? []
)
},
})
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,
isLoading:
listStatus === 'pending' ||
createMutation.status === 'pending' ||
updateMutation.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: 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,
listStatus,
errorList,
createMutation.status,
createMutation.error,
updateMutation.status,
updateMutation.error,
deleteMutation.status,
deleteMutation.error,
copyMutation.status,
copyMutation.error,
refetch,
createMutation.mutateAsync,
updateMutation.mutateAsync,
deleteMutation.mutateAsync,
copyMutation.mutateAsync,
]
)
return (
<TemplateContext.Provider value={value}>
{children}
</TemplateContext.Provider>
)
}
export const useTemplateContext = (): TemplateContextType => {
const ctx = useContext(TemplateContext)
if (!ctx)
throw new Error('useTemplateContext must be used within TemplateProvider')
return ctx
}
export default TemplateProvider