feat: tags page for mobiles
This commit is contained in:
@ -1,12 +1,14 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useMemo } from "react";
|
import { RefObject, useMemo, useRef } from "react";
|
||||||
|
import { IconTag } from "@tabler/icons-react";
|
||||||
import { SimpleGrid, Stack } from "@mantine/core";
|
import { SimpleGrid, Stack } from "@mantine/core";
|
||||||
import Action from "@/app/actions/components/Action/Action";
|
import Action from "@/app/actions/components/Action/Action";
|
||||||
import mobileButtonsData from "@/app/actions/data/mobileButtonsData";
|
import mobileButtonsData from "@/app/actions/data/mobileButtonsData";
|
||||||
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
|
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
|
||||||
import PageBlock from "@/components/layout/PageBlock/PageBlock";
|
import PageBlock from "@/components/layout/PageBlock/PageBlock";
|
||||||
import ProjectSelect from "@/components/selects/ProjectSelect/ProjectSelect";
|
import ProjectSelect from "@/components/selects/ProjectSelect/ProjectSelect";
|
||||||
|
import BuiltInLinkData from "@/types/BuiltInLinkData";
|
||||||
|
|
||||||
const PageBody = () => {
|
const PageBody = () => {
|
||||||
const { selectedProject, setSelectedProjectId, projects, modulesSet } =
|
const { selectedProject, setSelectedProjectId, projects, modulesSet } =
|
||||||
@ -20,6 +22,14 @@ const PageBody = () => {
|
|||||||
[modulesSet]
|
[modulesSet]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const commonActionsData: RefObject<BuiltInLinkData[]> = useRef([
|
||||||
|
{
|
||||||
|
icon: IconTag,
|
||||||
|
label: "Теги",
|
||||||
|
href: "/tags",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageBlock fullScreenMobile>
|
<PageBlock fullScreenMobile>
|
||||||
<Stack p={"xs"}>
|
<Stack p={"xs"}>
|
||||||
@ -33,7 +43,10 @@ const PageBody = () => {
|
|||||||
<SimpleGrid
|
<SimpleGrid
|
||||||
type={"container"}
|
type={"container"}
|
||||||
cols={2}>
|
cols={2}>
|
||||||
{filteredMobileButtonsData.map((data, index) => (
|
{[
|
||||||
|
...commonActionsData.current,
|
||||||
|
...filteredMobileButtonsData,
|
||||||
|
].map((data, index) => (
|
||||||
<Action
|
<Action
|
||||||
linkData={data}
|
linkData={data}
|
||||||
key={index}
|
key={index}
|
||||||
|
|||||||
@ -33,8 +33,6 @@ const useProjectsContextState = (): ProjectsContextState => {
|
|||||||
[projects, selectedProjectId]
|
[projects, selectedProjectId]
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(selectedProject);
|
|
||||||
|
|
||||||
const modulesSet = useMemo(
|
const modulesSet = useMemo(
|
||||||
() =>
|
() =>
|
||||||
new Set(
|
new Set(
|
||||||
|
|||||||
31
src/app/tags/components/PageBody/PageBody.tsx
Normal file
31
src/app/tags/components/PageBody/PageBody.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Center, Divider, Stack, Text } from "@mantine/core";
|
||||||
|
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
|
||||||
|
import TagsPageHeader from "@/app/tags/components/TagsPageHeader/TagsPageHeader";
|
||||||
|
import TagsTable from "@/drawers/common/ProjectEditorDrawer/tabs/TagsTab/components/TagsTable";
|
||||||
|
import { DealTagsContextProvider } from "@/drawers/common/ProjectEditorDrawer/tabs/TagsTab/contexts/DealTagsContext";
|
||||||
|
|
||||||
|
const PageBody = () => {
|
||||||
|
const { selectedProject } = useProjectsContext();
|
||||||
|
|
||||||
|
if (!selectedProject) {
|
||||||
|
return (
|
||||||
|
<Center>
|
||||||
|
<Text>Проект не найден</Text>
|
||||||
|
</Center>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DealTagsContextProvider project={selectedProject}>
|
||||||
|
<Stack gap={"md"}>
|
||||||
|
<TagsPageHeader project={selectedProject} />
|
||||||
|
<Divider />
|
||||||
|
<TagsTable />
|
||||||
|
</Stack>
|
||||||
|
</DealTagsContextProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PageBody;
|
||||||
32
src/app/tags/components/TagsPageHeader/TagsPageHeader.tsx
Normal file
32
src/app/tags/components/TagsPageHeader/TagsPageHeader.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { FC } from "react";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { IconChevronLeft, IconPlus } from "@tabler/icons-react";
|
||||||
|
import { Box, Group, Title } from "@mantine/core";
|
||||||
|
import useDealTagActions from "@/drawers/common/ProjectEditorDrawer/tabs/TagsTab/hooks/useDealTagActions";
|
||||||
|
import { ProjectSchema } from "@/lib/client";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
project: ProjectSchema;
|
||||||
|
};
|
||||||
|
|
||||||
|
const TagsPageHeader: FC<Props> = ({ project }) => {
|
||||||
|
const { onCreateClick } = useDealTagActions();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Group
|
||||||
|
mx={"xs"}
|
||||||
|
mt={"md"}
|
||||||
|
wrap={"nowrap"}
|
||||||
|
justify={"space-between"}>
|
||||||
|
<Link href={"/actions"}>
|
||||||
|
<IconChevronLeft />
|
||||||
|
</Link>
|
||||||
|
<Title order={5}>Теги проекта "{project.name}"</Title>
|
||||||
|
<Box onClick={onCreateClick}>
|
||||||
|
<IconPlus />
|
||||||
|
</Box>
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TagsPageHeader;
|
||||||
25
src/app/tags/page.tsx
Normal file
25
src/app/tags/page.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Suspense } from "react";
|
||||||
|
import { Center, Loader } from "@mantine/core";
|
||||||
|
import PageBody from "@/app/tags/components/PageBody/PageBody";
|
||||||
|
import PageBlock from "@/components/layout/PageBlock/PageBlock";
|
||||||
|
import PageContainer from "@/components/layout/PageContainer/PageContainer";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Page for mobiles only
|
||||||
|
*/
|
||||||
|
export default async function TagsPage() {
|
||||||
|
return (
|
||||||
|
<Suspense
|
||||||
|
fallback={
|
||||||
|
<Center h="50vh">
|
||||||
|
<Loader size="lg" />
|
||||||
|
</Center>
|
||||||
|
}>
|
||||||
|
<PageContainer>
|
||||||
|
<PageBlock fullScreenMobile>
|
||||||
|
<PageBody />
|
||||||
|
</PageBlock>
|
||||||
|
</PageContainer>
|
||||||
|
</Suspense>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
"use dealTag";
|
"use client";
|
||||||
|
|
||||||
import { DealTagsCrud, useDealTagsCrud } from "@/hooks/cruds/useDealTagsCrud";
|
import { DealTagsCrud, useDealTagsCrud } from "@/hooks/cruds/useDealTagsCrud";
|
||||||
import useDealTagsList from "@/hooks/lists/useDealTagsList";
|
import useDealTagsList from "@/hooks/lists/useDealTagsList";
|
||||||
@ -8,7 +8,6 @@ import makeContext from "@/lib/contextFactory/contextFactory";
|
|||||||
type DealTagsContextState = {
|
type DealTagsContextState = {
|
||||||
dealTags: DealTagSchema[];
|
dealTags: DealTagSchema[];
|
||||||
refetchDealTags: () => void;
|
refetchDealTags: () => void;
|
||||||
project: ProjectSchema;
|
|
||||||
dealTagsCrud: DealTagsCrud;
|
dealTagsCrud: DealTagsCrud;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,7 +26,6 @@ const useDealTagsContextState = ({ project }: Props): DealTagsContextState => {
|
|||||||
return {
|
return {
|
||||||
dealTags: dealTagsList.dealTags,
|
dealTags: dealTagsList.dealTags,
|
||||||
refetchDealTags: dealTagsList.refetch,
|
refetchDealTags: dealTagsList.refetch,
|
||||||
project,
|
|
||||||
dealTagsCrud,
|
dealTagsCrud,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -28,17 +28,14 @@ const useTagsTableColumns = ({ onDelete, onChange }: Props) => {
|
|||||||
{
|
{
|
||||||
title: "Название",
|
title: "Название",
|
||||||
accessor: "name",
|
accessor: "name",
|
||||||
width: 2,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Цвет",
|
title: "Цвет",
|
||||||
accessor: "tagColor.label",
|
accessor: "tagColor.label",
|
||||||
width: 2,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Пример",
|
title: "Пример",
|
||||||
accessor: "tagColor",
|
accessor: "tagColor",
|
||||||
width: 3,
|
|
||||||
render: tag => <DealTag tag={tag} />,
|
render: tag => <DealTag tag={tag} />,
|
||||||
},
|
},
|
||||||
] as DataTableColumn<DealTagSchema>[],
|
] as DataTableColumn<DealTagSchema>[],
|
||||||
|
|||||||
@ -60,6 +60,7 @@ import {
|
|||||||
getMarketplaces,
|
getMarketplaces,
|
||||||
getProductBarcodePdf,
|
getProductBarcodePdf,
|
||||||
getProducts,
|
getProducts,
|
||||||
|
getProject,
|
||||||
getProjects,
|
getProjects,
|
||||||
getServiceCategories,
|
getServiceCategories,
|
||||||
getServices,
|
getServices,
|
||||||
@ -214,6 +215,7 @@ import type {
|
|||||||
GetProductsData,
|
GetProductsData,
|
||||||
GetProductsError,
|
GetProductsError,
|
||||||
GetProductsResponse2,
|
GetProductsResponse2,
|
||||||
|
GetProjectData,
|
||||||
GetProjectsData,
|
GetProjectsData,
|
||||||
GetServiceCategoriesData,
|
GetServiceCategoriesData,
|
||||||
GetServicesData,
|
GetServicesData,
|
||||||
@ -2714,6 +2716,27 @@ export const deleteProjectMutation = (
|
|||||||
return mutationOptions;
|
return mutationOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getProjectQueryKey = (options: Options<GetProjectData>) =>
|
||||||
|
createQueryKey("getProject", options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Project
|
||||||
|
*/
|
||||||
|
export const getProjectOptions = (options: Options<GetProjectData>) => {
|
||||||
|
return queryOptions({
|
||||||
|
queryFn: async ({ queryKey, signal }) => {
|
||||||
|
const { data } = await getProject({
|
||||||
|
...options,
|
||||||
|
...queryKey[0],
|
||||||
|
signal,
|
||||||
|
throwOnError: true,
|
||||||
|
});
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
queryKey: getProjectQueryKey(options),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update Project
|
* Update Project
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -147,6 +147,9 @@ import type {
|
|||||||
GetProductsData,
|
GetProductsData,
|
||||||
GetProductsErrors,
|
GetProductsErrors,
|
||||||
GetProductsResponses,
|
GetProductsResponses,
|
||||||
|
GetProjectData,
|
||||||
|
GetProjectErrors,
|
||||||
|
GetProjectResponses,
|
||||||
GetProjectsData,
|
GetProjectsData,
|
||||||
GetProjectsResponses,
|
GetProjectsResponses,
|
||||||
GetServiceCategoriesData,
|
GetServiceCategoriesData,
|
||||||
@ -317,6 +320,8 @@ import {
|
|||||||
zGetProductBarcodePdfResponse2,
|
zGetProductBarcodePdfResponse2,
|
||||||
zGetProductsData,
|
zGetProductsData,
|
||||||
zGetProductsResponse2,
|
zGetProductsResponse2,
|
||||||
|
zGetProjectData,
|
||||||
|
zGetProjectResponse2,
|
||||||
zGetProjectsData,
|
zGetProjectsData,
|
||||||
zGetProjectsResponse2,
|
zGetProjectsResponse2,
|
||||||
zGetServiceCategoriesData,
|
zGetServiceCategoriesData,
|
||||||
@ -2090,6 +2095,29 @@ export const deleteProject = <ThrowOnError extends boolean = false>(
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Project
|
||||||
|
*/
|
||||||
|
export const getProject = <ThrowOnError extends boolean = false>(
|
||||||
|
options: Options<GetProjectData, ThrowOnError>
|
||||||
|
) => {
|
||||||
|
return (options.client ?? _heyApiClient).get<
|
||||||
|
GetProjectResponses,
|
||||||
|
GetProjectErrors,
|
||||||
|
ThrowOnError
|
||||||
|
>({
|
||||||
|
requestValidator: async data => {
|
||||||
|
return await zGetProjectData.parseAsync(data);
|
||||||
|
},
|
||||||
|
responseType: "json",
|
||||||
|
responseValidator: async data => {
|
||||||
|
return await zGetProjectResponse2.parseAsync(data);
|
||||||
|
},
|
||||||
|
url: "/crm/v1/project/{pk}",
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update Project
|
* Update Project
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1400,6 +1400,13 @@ export type GetProductsResponse = {
|
|||||||
paginationInfo: PaginationInfoSchema;
|
paginationInfo: PaginationInfoSchema;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetProjectResponse
|
||||||
|
*/
|
||||||
|
export type GetProjectResponse = {
|
||||||
|
entity: ProjectSchema;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetProjectsResponse
|
* GetProjectsResponse
|
||||||
*/
|
*/
|
||||||
@ -4451,6 +4458,37 @@ export type DeleteProjectResponses = {
|
|||||||
export type DeleteProjectResponse2 =
|
export type DeleteProjectResponse2 =
|
||||||
DeleteProjectResponses[keyof DeleteProjectResponses];
|
DeleteProjectResponses[keyof DeleteProjectResponses];
|
||||||
|
|
||||||
|
export type GetProjectData = {
|
||||||
|
body?: never;
|
||||||
|
path: {
|
||||||
|
/**
|
||||||
|
* Pk
|
||||||
|
*/
|
||||||
|
pk: number;
|
||||||
|
};
|
||||||
|
query?: never;
|
||||||
|
url: "/crm/v1/project/{pk}";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetProjectErrors = {
|
||||||
|
/**
|
||||||
|
* Validation Error
|
||||||
|
*/
|
||||||
|
422: HttpValidationError;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetProjectError = GetProjectErrors[keyof GetProjectErrors];
|
||||||
|
|
||||||
|
export type GetProjectResponses = {
|
||||||
|
/**
|
||||||
|
* Successful Response
|
||||||
|
*/
|
||||||
|
200: GetProjectResponse;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type GetProjectResponse2 =
|
||||||
|
GetProjectResponses[keyof GetProjectResponses];
|
||||||
|
|
||||||
export type UpdateProjectData = {
|
export type UpdateProjectData = {
|
||||||
body: UpdateProjectRequest;
|
body: UpdateProjectRequest;
|
||||||
path: {
|
path: {
|
||||||
|
|||||||
@ -957,6 +957,13 @@ export const zGetProductsResponse = z.object({
|
|||||||
paginationInfo: zPaginationInfoSchema,
|
paginationInfo: zPaginationInfoSchema,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetProjectResponse
|
||||||
|
*/
|
||||||
|
export const zGetProjectResponse = z.object({
|
||||||
|
entity: zProjectSchema,
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetProjectsResponse
|
* GetProjectsResponse
|
||||||
*/
|
*/
|
||||||
@ -2329,6 +2336,19 @@ export const zDeleteProjectData = z.object({
|
|||||||
*/
|
*/
|
||||||
export const zDeleteProjectResponse2 = zDeleteProjectResponse;
|
export const zDeleteProjectResponse2 = zDeleteProjectResponse;
|
||||||
|
|
||||||
|
export const zGetProjectData = z.object({
|
||||||
|
body: z.optional(z.never()),
|
||||||
|
path: z.object({
|
||||||
|
pk: z.int(),
|
||||||
|
}),
|
||||||
|
query: z.optional(z.never()),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Successful Response
|
||||||
|
*/
|
||||||
|
export const zGetProjectResponse2 = zGetProjectResponse;
|
||||||
|
|
||||||
export const zUpdateProjectData = z.object({
|
export const zUpdateProjectData = z.object({
|
||||||
body: zUpdateProjectRequest,
|
body: zUpdateProjectRequest,
|
||||||
path: z.object({
|
path: z.object({
|
||||||
|
|||||||
9
src/types/BuiltInLinkData.ts
Normal file
9
src/types/BuiltInLinkData.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { IconPlus } from "@tabler/icons-react";
|
||||||
|
|
||||||
|
type BuiltInLinkData = {
|
||||||
|
icon: typeof IconPlus;
|
||||||
|
label: string;
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BuiltInLinkData;
|
||||||
Reference in New Issue
Block a user