группы

This commit is contained in:
Artem
2025-08-03 15:19:07 +03:00
parent 95e89b27bf
commit 4d69217967
17 changed files with 3549 additions and 84 deletions

View File

@@ -0,0 +1,142 @@
import { Group } from '@/type/template'
// Интерфейсы для API групп
export interface GetGroupsOutput {
groups: Group[]
}
export interface GetGroupOutput {
group: Group | null
}
export interface CreateGroupInput {
name: string
order?: number
}
export interface CreateGroupOutput {
id: string
}
export interface PatchGroupInput {
name?: string | null
order?: number | null
}
export interface PatchGroupOutput extends Group {}
// API получение всех групп
export async function getGroupsApi(): Promise<GetGroupsOutput> {
try {
const response = await fetch('/api/groups/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const result: GetGroupsOutput = await response.json()
return result
} catch (error) {
console.error('Ошибка при получении групп:', error)
throw new Error('Ошибка при получении групп с сервера')
}
}
// API получение конкретной группы
export async function getGroupApi(groupId: string): Promise<GetGroupOutput> {
try {
const response = await fetch(`/api/groups/${groupId}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const result: GetGroupOutput = await response.json()
return result
} catch (error) {
console.error('Ошибка при получении группы:', error)
throw new Error('Ошибка при получении группы с сервера')
}
}
// API создание группы
export async function createGroupApi(
group: CreateGroupInput
): Promise<CreateGroupOutput> {
try {
const response = await fetch('/api/groups/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(group),
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const result: CreateGroupOutput = await response.json()
return result
} catch (error) {
console.error('Ошибка при создании группы:', error)
throw new Error('Ошибка при создании группы на сервере')
}
}
// API обновление группы
export async function patchGroupApi(
groupId: string,
group: PatchGroupInput
): Promise<PatchGroupOutput> {
try {
const response = await fetch(`/api/groups/${groupId}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(group),
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const result: PatchGroupOutput = await response.json()
return result
} catch (error) {
console.error('Ошибка при обновлении группы:', error)
throw new Error('Ошибка при обновлении группы на сервере')
}
}
// API удаление группы (если потребуется)
export async function deleteGroupApi(groupId: string): Promise<{success: boolean}> {
try {
const response = await fetch(`/api/groups/${groupId}`, {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
},
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
return { success: true }
} catch (error) {
console.error('Ошибка при удалении группы:', error)
throw new Error('Ошибка при удалении группы на сервере')
}
}

View File

@@ -0,0 +1,137 @@
import {
createGroupApi,
CreateGroupInput,
deleteGroupApi,
getGroupsApi,
patchGroupApi,
PatchGroupInput
} from '@/entity/group/api/groupApiService'
import { Group } from '@/type/template'
import {
QueryClient,
useMutation,
useQuery,
useQueryClient,
} from '@tanstack/react-query'
import { createContext, ReactNode, useContext, useMemo } from 'react'
export const queryClient = new QueryClient()
interface GroupContextType {
groups: Group[]
isLoading: boolean
error: Error | null
refetchGroups: () => void
addGroup: (data: CreateGroupInput) => Promise<Group>
updateGroup: (
groupId: string,
data: PatchGroupInput
) => Promise<Group>
deleteGroup: (groupId: string) => Promise<string>
getGroupById: (groupId: string) => Group | undefined
}
const GroupContext = createContext<GroupContextType | undefined>(undefined)
export const GroupProvider: React.FC<{ children: ReactNode }> = ({
children,
}) => {
const client = useQueryClient()
const {
data: groups = [],
status: listStatus,
error: errorList,
refetch,
} = useQuery<Group[], Error>({
queryKey: ['groups'],
queryFn: async () => {
const { groups: apiList } = await getGroupsApi()
return apiList.sort((a, b) => a.order - b.order)
},
})
const createMutation = useMutation({
mutationFn: async (group: CreateGroupInput) => {
const { id } = await createGroupApi(group)
// Возвращаем созданную группу, получив её с сервера
const { groups: updatedGroups } = await getGroupsApi()
const newGroup = updatedGroups.find(g => g.id === id)
if (!newGroup) throw new Error('Группа не найдена после создания')
return newGroup
},
onSuccess: () => {
client.invalidateQueries({ queryKey: ['groups'] })
},
})
const updateMutation = useMutation({
mutationFn: async ({
groupId,
data,
}: {
groupId: string
data: PatchGroupInput
}) => {
return await patchGroupApi(groupId, data)
},
onSuccess: () => {
client.invalidateQueries({ queryKey: ['groups'] })
},
})
const deleteMutation = useMutation({
mutationFn: async (groupId: string) => {
await deleteGroupApi(groupId)
return groupId
},
onSuccess: () => {
client.invalidateQueries({ queryKey: ['groups'] })
},
})
const getGroupById = (groupId: string) =>
groups.find(group => group.id === groupId)
const value = useMemo(
() => ({
groups,
isLoading:
listStatus === 'pending' ||
createMutation.status === 'pending' ||
updateMutation.status === 'pending' ||
deleteMutation.status === 'pending',
error:
(errorList as Error) ||
(createMutation.error as Error) ||
(updateMutation.error as Error) ||
(deleteMutation.error as Error) ||
null,
refetchGroups: refetch,
addGroup: createMutation.mutateAsync,
updateGroup: async (groupId: string, data: PatchGroupInput) =>
updateMutation.mutateAsync({ groupId, data }),
deleteGroup: deleteMutation.mutateAsync,
getGroupById,
}),
[
groups,
listStatus,
errorList,
createMutation,
updateMutation,
deleteMutation,
refetch,
]
)
return <GroupContext.Provider value={value}>{children}</GroupContext.Provider>
}
export const useGroupContext = (): GroupContextType => {
const context = useContext(GroupContext)
if (!context) {
throw new Error('useGroupContext must be used within a GroupProvider')
}
return context
}