llzai's picture
Upload 1793 files
9853396 verified
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import { graphqlRequest } from '@/gql/graphql';
import { toast } from 'sonner';
import i18n from '@/lib/i18n';
import { useErrorHandler } from '@/hooks/use-error-handler';
import { Project, ProjectConnection, CreateProjectInput, UpdateProjectInput, projectConnectionSchema, projectSchema } from './schema';
// GraphQL queries and mutations
const PROJECTS_QUERY = `
query GetProjects($first: Int, $after: Cursor, $orderBy: ProjectOrder, $where: ProjectWhereInput) {
projects(first: $first, after: $after, orderBy: $orderBy, where: $where) {
edges {
node {
id
createdAt
updatedAt
name
description
status
}
cursor
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
totalCount
}
}
`;
const CREATE_PROJECT_MUTATION = `
mutation CreateProject($input: CreateProjectInput!) {
createProject(input: $input) {
id
name
description
status
createdAt
updatedAt
}
}
`;
const UPDATE_PROJECT_MUTATION = `
mutation UpdateProject($id: ID!, $input: UpdateProjectInput!) {
updateProject(id: $id, input: $input) {
id
name
description
status
createdAt
updatedAt
}
}
`;
const UPDATE_PROJECT_STATUS_MUTATION = `
mutation UpdateProjectStatus($id: ID!, $status: ProjectStatus!) {
updateProjectStatus(id: $id, status: $status) {
id
name
description
status
createdAt
updatedAt
}
}
`;
const MY_PROJECTS_QUERY = `
query MyProjects {
myProjects {
id
name
description
status
createdAt
updatedAt
}
}
`;
// Query hooks
export function useProjects(
variables: {
first?: number;
after?: string;
orderBy?: { field: 'CREATED_AT'; direction: 'ASC' | 'DESC' };
where?: any;
} = {}
) {
const { handleError } = useErrorHandler();
const { t } = useTranslation();
const queryVariables = {
...variables,
orderBy: variables.orderBy || { field: 'CREATED_AT', direction: 'DESC' },
};
return useQuery({
queryKey: ['projects', queryVariables],
queryFn: async () => {
try {
const data = await graphqlRequest<{ projects: ProjectConnection }>(PROJECTS_QUERY, queryVariables);
return projectConnectionSchema.parse(data?.projects);
} catch (error) {
handleError(error, t('projects.errors.loadProjectsFailed'));
throw error;
}
},
});
}
export function useProject(id: string) {
const { handleError } = useErrorHandler();
const { t } = useTranslation();
return useQuery({
queryKey: ['project', id],
queryFn: async () => {
try {
const data = await graphqlRequest<{ projects: ProjectConnection }>(PROJECTS_QUERY, { where: { id } });
const project = data.projects.edges[0]?.node;
if (!project) {
throw new Error('Project not found');
}
return projectSchema.parse(project);
} catch (error) {
handleError(error, t('projects.errors.loadProjectDetailFailed'));
throw error;
}
},
enabled: !!id,
});
}
export function useMyProjects() {
const { handleError } = useErrorHandler();
const { t } = useTranslation();
return useQuery({
queryKey: ['myProjects'],
queryFn: async () => {
try {
const data = await graphqlRequest<{ myProjects: Project[] }>(MY_PROJECTS_QUERY);
if (!data || !data.myProjects) {
return [];
}
// myProjects 直接返回项目数组,不是 connection 格式
const projects = data.myProjects.map((project) => projectSchema.parse(project));
return projects;
} catch (error) {
handleError(error, t('projects.errors.loadMyProjectsFailed'));
return [];
}
},
});
}
// Mutation hooks
export function useCreateProject() {
const queryClient = useQueryClient();
const { handleError } = useErrorHandler();
return useMutation({
mutationFn: async (input: CreateProjectInput) => {
try {
const data = await graphqlRequest<{ createProject: Project }>(CREATE_PROJECT_MUTATION, { input });
return projectSchema.parse(data.createProject);
} catch (error) {
handleError(error, i18n.t('projects.errors.createProjectFailed'));
throw error;
}
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['projects'] });
queryClient.invalidateQueries({ queryKey: ['myProjects'] });
toast.success(i18n.t('common.success.projectCreated'));
},
});
}
export function useUpdateProject() {
const queryClient = useQueryClient();
const { handleError } = useErrorHandler();
return useMutation({
mutationFn: async ({ id, input }: { id: string; input: UpdateProjectInput }) => {
try {
const data = await graphqlRequest<{ updateProject: Project }>(UPDATE_PROJECT_MUTATION, { id, input });
return projectSchema.parse(data.updateProject);
} catch (error) {
handleError(error, i18n.t('projects.errors.updateProjectFailed'));
throw error;
}
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['projects'] });
queryClient.invalidateQueries({ queryKey: ['project'] });
queryClient.invalidateQueries({ queryKey: ['myProjects'] });
toast.success(i18n.t('common.success.projectUpdated'));
},
});
}
export function useArchiveProject() {
const queryClient = useQueryClient();
const { handleError } = useErrorHandler();
return useMutation({
mutationFn: async (id: string) => {
try {
const data = await graphqlRequest<{ updateProjectStatus: Project }>(UPDATE_PROJECT_STATUS_MUTATION, {
id,
status: 'archived',
});
return projectSchema.parse(data.updateProjectStatus);
} catch (error) {
handleError(error, i18n.t('projects.errors.archiveProjectFailed'));
throw error;
}
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['projects'] });
queryClient.invalidateQueries({ queryKey: ['project'] });
queryClient.invalidateQueries({ queryKey: ['myProjects'] });
toast.success(i18n.t('common.success.projectArchived'));
},
});
}
export function useActivateProject() {
const queryClient = useQueryClient();
const { handleError } = useErrorHandler();
return useMutation({
mutationFn: async (id: string) => {
try {
const data = await graphqlRequest<{ updateProjectStatus: Project }>(UPDATE_PROJECT_STATUS_MUTATION, {
id,
status: 'active',
});
return projectSchema.parse(data.updateProjectStatus);
} catch (error) {
handleError(error, i18n.t('projects.errors.activateProjectFailed'));
throw error;
}
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['projects'] });
queryClient.invalidateQueries({ queryKey: ['project'] });
queryClient.invalidateQueries({ queryKey: ['myProjects'] });
toast.success(i18n.t('common.success.projectActivated'));
},
});
}