feat: table view for mobiles

This commit is contained in:
2025-10-06 09:37:58 +04:00
parent 665625557d
commit b316cf4f7a
14 changed files with 142 additions and 106 deletions

View File

@ -6,9 +6,11 @@ import { useDealsContext } from "@/app/deals/contexts/DealsContext";
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
import BaseTable from "@/components/ui/BaseTable/BaseTable";
import { useDrawersContext } from "@/drawers/DrawersContext";
import useIsMobile from "@/hooks/utils/useIsMobile";
import { DealSchema } from "@/lib/client";
const DealsTable: FC = () => {
const isMobile = useIsMobile();
const { selectedProject } = useProjectsContext();
const { deals, paginationInfo, page, setPage, sortingForm, dealsCrud } =
useDealsContext();
@ -33,9 +35,11 @@ const DealsTable: FC = () => {
return (
<Stack
p={isMobile ? "xs" : ""}
gap={"xs"}
h={"100%"}>
<BaseTable
withTableBorder
records={[...deals]}
columns={columns}
sortStatus={{

View File

@ -1,7 +1,8 @@
import { useMemo } from "react";
import { IconEdit } from "@tabler/icons-react";
import { DataTableColumn } from "mantine-datatable";
import { ActionIcon, Tooltip } from "@mantine/core";
import ActionIconWithTip from "@/components/ui/ActionIconWithTip/ActionIconWithTip";
import useIsMobile from "@/hooks/utils/useIsMobile";
import { DealSchema } from "@/lib/client";
import { utcDateTimeToLocalString } from "@/utils/datetime";
@ -10,44 +11,43 @@ type Props = {
};
const useDealsTableColumns = ({ onEditClick }: Props) => {
const isMobile = useIsMobile();
return useMemo(
() =>
[
{
accessor: "actions",
title: "Действия",
title: isMobile ? "" : "Действия",
sortable: false,
textAlign: "center",
width: "0%",
render: deal => (
<Tooltip label="Редактировать">
<ActionIcon
bdrs={"md"}
size={"lg"}
onClick={() => onEditClick(deal)}
variant={"default"}>
<IconEdit />
</ActionIcon>
</Tooltip>
<ActionIconWithTip
tipLabel={"Редактировать"}
onClick={() => onEditClick(deal)}
variant={isMobile ? "subtle" : "default"}>
<IconEdit />
</ActionIconWithTip>
),
},
{
accessor: "id",
title: "Номер",
title: isMobile ? "№" : "Номер",
sortable: true,
width: "30%",
width: "20%",
},
{
accessor: "name",
title: "Название",
width: "40%",
width: "45%",
},
{
title: "Дата создания",
accessor: "createdAt",
render: deal => utcDateTimeToLocalString(deal.createdAt),
sortable: true,
width: "30%",
width: "35%",
},
] as DataTableColumn<DealSchema>[],
[onEditClick]

View File

@ -12,7 +12,11 @@ import { DealsFiltersForm } from "@/app/deals/hooks/useDealsFilters";
import SmallPageBlock from "@/components/layout/SmallPageBlock/SmallPageBlock";
import useIsMobile from "@/hooks/utils/useIsMobile";
export type View = "board" | "table" | "schedule";
export enum View {
BOARD = "board",
TABLE = "table",
SCHEDULE = "schedule"
}
type Props = {
view: View;
@ -42,7 +46,7 @@ const TopToolPanel: FC<Props> = ({ view, setView }) => {
onChange: (values: DealsFiltersForm) =>
dealsFiltersForm.setValues(values),
project: selectedProject,
boardAndStatusEnabled: view === "table",
boardAndStatusEnabled: view === View.TABLE,
},
});
};

View File

@ -16,15 +16,15 @@ type Props = {
const ViewSelector: FC<Props> = ({ value, onChange }) => {
const views = [
{
value: "board" as View,
value: View.BOARD,
icon: <IconLayoutDashboard />,
},
{
value: "table" as View,
value: View.TABLE,
icon: <IconMenu2 />,
},
{
value: "schedule" as View,
value: View.SCHEDULE,
icon: <IconCalendarWeekFilled />,
},
];

View File

@ -1,9 +1,7 @@
"use client";
import { useState } from "react";
import TopToolPanel, {
View,
} from "@/app/deals/components/desktop/TopToolPanel/TopToolPanel";
import { Box } from "@mantine/core";
import TopToolPanel from "@/app/deals/components/desktop/TopToolPanel/TopToolPanel";
import {
BoardView,
ScheduleView,
@ -12,11 +10,14 @@ import {
import { useBoardsContext } from "@/app/deals/contexts/BoardsContext";
import { DealsContextProvider } from "@/app/deals/contexts/DealsContext";
import { useProjectsContext } from "@/app/deals/contexts/ProjectsContext";
import useView from "@/app/deals/hooks/useView";
import PageBlock from "@/components/layout/PageBlock/PageBlock";
const PageBody = () => {
const { selectedBoard } = useBoardsContext();
const { selectedProject } = useProjectsContext();
const [view, setView] = useState<View>("board");
const { view, setView } = useView();
const getViewContent = () => {
switch (view) {
@ -42,7 +43,11 @@ const PageBody = () => {
view={view}
setView={setView}
/>
{getViewContent()}
<PageBlock
fullScreenMobile
style={{ flex: 1 }}>
<Box h={"100%"}>{getViewContent()}</Box>
</PageBlock>
</DealsContextProvider>
);
};

View File

@ -1,12 +1,11 @@
import { Space } from "@mantine/core";
import MainBlockHeader from "@/app/deals/components/mobile/MainBlockHeader/MainBlockHeader";
import Funnel from "@/app/deals/components/shared/Funnel/Funnel";
import PageBlock from "@/components/layout/PageBlock/PageBlock";
export const BoardView = () => (
<PageBlock style={{ height: "100%" }}>
<>
<MainBlockHeader />
<Space h="md" />
<Funnel />
</PageBlock>
</>
);

View File

@ -1,5 +1,3 @@
import PageBlock from "@/components/layout/PageBlock/PageBlock";
export const ScheduleView = () => {
return <PageBlock>-</PageBlock>;
return <>-</>;
};

View File

@ -1,8 +1,3 @@
import DealsTable from "@/app/deals/components/desktop/DealsTable/DealsTable";
import PageBlock from "@/components/layout/PageBlock/PageBlock";
export const TableView = () => (
<PageBlock style={{ height: "100%" }}>
<DealsTable />
</PageBlock>
);
export const TableView = () => <DealsTable />;

View File

@ -0,0 +1,34 @@
import { useEffect, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { View } from "@/app/deals/components/desktop/TopToolPanel/TopToolPanel";
const useView = () => {
const router = useRouter();
const searchParams = useSearchParams();
const viewsArray = Object.values(View);
const [view, setView] = useState<View>(() => {
const urlView = searchParams.get("view") as View;
return urlView && viewsArray.includes(urlView) ? urlView : View.BOARD;
});
useEffect(() => {
const urlView = searchParams.get("view") as View;
if (urlView && viewsArray.includes(urlView)) {
setView(urlView);
}
}, [searchParams]);
useEffect(() => {
const params = new URLSearchParams(searchParams.toString());
if (params.get("view") === view) return;
router.replace(`?view=${view}`);
}, [view]);
return {
view,
setView,
};
};
export default useView;