1st approach for projects, items, db structure

This commit is contained in:
Jurgis Sakalauskas
2025-10-13 14:04:22 +03:00
parent ad2cf25bfd
commit afc3da3e65
45 changed files with 4743 additions and 117 deletions
+44
View File
@@ -0,0 +1,44 @@
import {
createItemPrice,
fetchItemPrices,
type CreateItemPricePayload,
type ItemPricesResponse
} from '../api/item-prices';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
const DEFAULT_LIMIT = 50;
export const itemPricesKeys = {
all: ['itemPrices'] as const,
list: (itemId: string) => [...itemPricesKeys.all, itemId, 'list'] as const
};
export const useItemPricesQuery = (
itemId: string | undefined,
enabled: boolean
) =>
useQuery<ItemPricesResponse>({
queryKey: itemId ? itemPricesKeys.list(itemId) : ['itemPrices', 'missing'],
enabled: enabled && Boolean(itemId),
queryFn: ({ signal }) => fetchItemPrices(itemId!, { limit: DEFAULT_LIMIT, offset: 0, signal })
});
export const useCreateItemPriceMutation = (itemId: string | undefined) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (payload: CreateItemPricePayload) => {
if (!itemId) {
throw new Error('itemId is required to create a price');
}
return createItemPrice(itemId, payload);
},
onSuccess: () => {
if (!itemId) {
return;
}
queryClient.invalidateQueries({ queryKey: itemPricesKeys.list(itemId) });
}
});
};
+100
View File
@@ -0,0 +1,100 @@
import {
createProject,
fetchProject,
fetchProjects,
updateProject,
type CreateProjectPayload,
type Project,
type ProjectsListResponse,
type UpdateProjectPayload
} from '../api/projects';
import {
createItem,
fetchProjectItems,
type CreateItemPayload,
type ProjectItemsResponse
} from '../api/items';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
const DEFAULT_LIMIT = 50;
export const projectsKeys = {
all: ['projects'] as const,
list: () => [...projectsKeys.all, 'list'] as const,
detail: (projectId: string) =>
[...projectsKeys.all, 'detail', projectId] as const,
items: (projectId: string) =>
[...projectsKeys.detail(projectId), 'items'] as const
};
export const useProjectsQuery = () =>
useQuery<ProjectsListResponse>({
queryKey: projectsKeys.list(),
queryFn: ({ signal }) => fetchProjects({ limit: DEFAULT_LIMIT, offset: 0, signal })
});
export const useProjectQuery = (projectId: string | undefined) =>
useQuery<Project>({
queryKey: projectId ? projectsKeys.detail(projectId) : ['project', 'missing'],
enabled: Boolean(projectId),
queryFn: ({ signal }) => fetchProject(projectId!, { signal })
});
export const useProjectItemsQuery = (projectId: string | undefined) =>
useQuery<ProjectItemsResponse>({
queryKey: projectId ? projectsKeys.items(projectId) : ['project', 'items', 'missing'],
enabled: Boolean(projectId),
queryFn: ({ signal }) =>
fetchProjectItems(projectId!, { limit: DEFAULT_LIMIT, offset: 0, signal })
});
export const useCreateProjectMutation = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (payload: CreateProjectPayload) => createProject(payload),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: projectsKeys.list() });
}
});
};
export const useUpdateProjectMutation = (projectId: string | undefined) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (payload: UpdateProjectPayload) => {
if (!projectId) {
throw new Error('projectId is required to update a project');
}
return updateProject(projectId, payload);
},
onSuccess: () => {
if (!projectId) {
return;
}
queryClient.invalidateQueries({ queryKey: projectsKeys.detail(projectId) });
queryClient.invalidateQueries({ queryKey: projectsKeys.list() });
}
});
};
export const useCreateItemMutation = (projectId: string | undefined) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (payload: CreateItemPayload) => {
if (!projectId) {
throw new Error('projectId is required to create an item');
}
return createItem(projectId, payload);
},
onSuccess: () => {
if (!projectId) {
return;
}
queryClient.invalidateQueries({ queryKey: projectsKeys.items(projectId) });
queryClient.invalidateQueries({ queryKey: projectsKeys.detail(projectId) });
}
});
};
-14
View File
@@ -1,14 +0,0 @@
import { useQuery } from '@tanstack/react-query';
import { getHealth, type HealthResponse } from '../api/health';
const healthQueryKeys = {
all: ['health'] as const
};
export function useHealthQuery() {
return useQuery<HealthResponse>({
queryKey: healthQueryKeys.all,
queryFn: getHealth,
staleTime: 30_000
});
}