233 lines
6.2 KiB
TypeScript
233 lines
6.2 KiB
TypeScript
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
|