Переглянути джерело

update the status in project list, and can click the status to route to edit page and auto click button

pull/5/head
cyril.tsui 6 місяці тому
джерело
коміт
ca6cfecdaa
3 змінених файлів з 129 додано та 16 видалено
  1. +17
    -1
      src/components/CreateProject/CreateProject.tsx
  2. +35
    -2
      src/components/ProjectSearch/ProjectSearch.tsx
  3. +77
    -13
      src/components/SearchResults/SearchResults.tsx

+ 17
- 1
src/components/CreateProject/CreateProject.tsx Переглянути файл

@@ -8,7 +8,7 @@ import Button, { ButtonProps } from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import Tab from "@mui/material/Tab";
import Tabs, { TabsProps } from "@mui/material/Tabs";
import { useRouter } from "next/navigation";
import { useRouter, useSearchParams } from "next/navigation";
import React, {
useCallback,
useEffect,
@@ -588,6 +588,21 @@ const CreateProject: React.FC<Props> = ({
}, t);
}, [draftId, router]);

// Auto click the button
const buttonRef = useRef<HTMLButtonElement>(null)
const searchParams = useSearchParams()

useEffect(() => {
if (buttonRef) {
const autoClickButton = searchParams.get("autoClick")
// const autoClickList = ["start", "complete", "reopen"]
if(autoClickButton && autoClickButton === "true") {
buttonRef.current?.click()
}
}
}, [buttonRef])

return (
<>
<FormProvider {...formProps}>
@@ -629,6 +644,7 @@ const CreateProject: React.FC<Props> = ({
<Stack direction="row" gap={1}>
{/* {!formProps.getValues("projectActualStart") && ( */}
<Button
ref={buttonRef}
name={buttonData.buttonName}
type="submit"
variant="contained"


+ 35
- 2
src/components/ProjectSearch/ProjectSearch.tsx Переглянути файл

@@ -7,7 +7,7 @@ import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults";
import EditNote from "@mui/icons-material/EditNote";
import uniq from "lodash/uniq";
import { useRouter } from "next/navigation";
import { useRouter, useSearchParams } from "next/navigation";
import { MAINTAIN_PROJECT } from "@/middleware";
import { reverse, uniqBy } from "lodash";
import { loadDrafts } from "@/app/utils/draftUtils";
@@ -141,6 +141,32 @@ const ProjectSearch: React.FC<Props> = ({
[router],
);

const onProjectStatusClick = useCallback(
(project: ProjectResultOrDraft) => {
const status = project.status.toLocaleLowerCase()
console.log(status)

if (status && statusList.includes(status)) {
/* switch (status) {
case "pending to start":
router.push(`/projects/edit?id=${project.id}&autoClick=start`);
break;
case "on-going":
router.push(`/projects/edit?id=${project.id}&autoClick=complete`);
break;
case "completed":
router.push(`/projects/edit?id=${project.id}&autoClick=reopen`);
break;
} */
router.push(`/projects/edit?id=${project.id}&autoClick=true`);
}
},
[router],
);

const statusList = ["pending to start", "on-going","completed"]
const ignoreStatusList = ["draft", "deleted"]

const columns = useMemo<Column<ProjectResult>[]>(
() => [
{
@@ -165,7 +191,14 @@ const ProjectSearch: React.FC<Props> = ({
{ name: "category", label: t("Project Category") },
{ name: "team", label: t("Team") },
{ name: "client", label: t("Client") },
{ name: "status", label: t("Status") },
{
name: "status",
label: t("Status"),
type: "link",
onClick: onProjectStatusClick,
underlines: ignoreStatusList.reduce((acc, cur) => ({...acc, [cur]: "none"}), {}),
colors: ignoreStatusList.reduce((acc, cur) => ({...acc, [cur]: "inherit"}), {}),
}
],
[t, onProjectClick],
);


+ 77
- 13
src/components/SearchResults/SearchResults.tsx Переглянути файл

@@ -17,6 +17,7 @@ import { useTranslation } from "react-i18next";
import { convertDateArrayToString, moneyFormatter } from "@/app/utils/formatUtil";
import DoneIcon from '@mui/icons-material/Done';
import CloseIcon from '@mui/icons-material/Close';
import { Button, Link, LinkOwnProps } from "@mui/material";

export interface ResultWithId {
id: string | number;
@@ -25,7 +26,6 @@ export interface ResultWithId {
interface BaseColumn<T extends ResultWithId> {
name: keyof T;
label: string;
color?: IconButtonOwnProps["color"];
needTranslation?: boolean;
type?: string;
isHidden?: boolean;
@@ -34,13 +34,25 @@ interface BaseColumn<T extends ResultWithId> {
interface ColumnWithAction<T extends ResultWithId> extends BaseColumn<T> {
onClick: (item: T) => void;
buttonIcon: React.ReactNode;
color?: IconButtonOwnProps["color"];
disabled?: boolean;
disabledRows?: { [columnName in keyof T]: string[] }; // Filter the row which is going to be disabled
disabledRows?: { [columnValue in keyof T]: string[] }; // Filter the row which is going to be disabled
}

interface LinkColumn<T extends ResultWithId> extends BaseColumn<T> {
// href: string;
onClick: (item: T) => void;
underline: LinkOwnProps["underline"];
underlines: { [columnValue in keyof T]: LinkOwnProps["underline"] };
color: LinkOwnProps["color"];
colors: { [columnValue in keyof T]: LinkOwnProps["color"] };
}

export type Column<T extends ResultWithId> =
| BaseColumn<T>
| ColumnWithAction<T>;
| ColumnWithAction<T>
| LinkColumn<T>
;

interface Props<T extends ResultWithId> {
items: T[];
@@ -55,6 +67,12 @@ function isActionColumn<T extends ResultWithId>(
return Boolean((column as ColumnWithAction<T>).onClick);
}

function isLinkColumn<T extends ResultWithId>(
column: Column<T>,
): column is LinkColumn<T> {
return column.type === "link";
}

function SearchResults<T extends ResultWithId>({
items,
columns,
@@ -101,6 +119,43 @@ function SearchResults<T extends ResultWithId>({
return false;
};

function convertObjectKeysToLowercase<T extends object>(obj: T): object | undefined {
return obj ? Object.fromEntries(
Object.entries(obj).map(([key, value]) => [key.toLowerCase(), value])
) : undefined;
}

// Link Component Functions
function handleLinkColors<T extends ResultWithId>(
column: LinkColumn<T>,
value: T[keyof T],
): LinkOwnProps["color"] {
const colors = convertObjectKeysToLowercase(column.colors);
console.log(colors)
const valueKey = String(value).toLowerCase() as keyof typeof colors;

if (colors && valueKey in colors) {
return colors[valueKey];
}

return column.color ?? "primary";
};

function handleLinkUnderlines<T extends ResultWithId>(
column: LinkColumn<T>,
value: T[keyof T],
): LinkOwnProps["underline"] {
const underlines = convertObjectKeysToLowercase(column.underlines);
console.log(underlines)
const valueKey = String(value).toLowerCase() as keyof typeof underlines;

if (underlines && valueKey in underlines) {
return underlines[valueKey];
}

return column.underline ?? "always";
};

const table = (
<>
<TableContainer sx={{ maxHeight: 440 }}>
@@ -125,15 +180,15 @@ function SearchResults<T extends ResultWithId>({

return (
<TableCell key={`${columnName.toString()}-${idx}`}>
{isActionColumn(column) ? (
<IconButton
color={column.color ?? "primary"}
onClick={() => column.onClick(item)}
disabled={Boolean(column.disabled) || Boolean(disabledRows(column, item))}
>
{column.buttonIcon}
</IconButton>
) :
{isActionColumn(column) && !column?.type ? (
<IconButton
color={column.color ?? "primary"}
onClick={() => column.onClick(item)}
disabled={Boolean(column.disabled) || Boolean(disabledRows(column, item))}
>
{column.buttonIcon}
</IconButton>
) :
column?.type === "date" ? (
<>{convertDateArrayToString(item[columnName] as number[])}</>
) :
@@ -143,9 +198,18 @@ function SearchResults<T extends ResultWithId>({
column?.type === "checkbox" ? (
Boolean(item[columnName]) ?
<DoneIcon color="primary" /> : <CloseIcon color="error"/>
) :
isLinkColumn(column) ? (
<Link
onClick={() => column.onClick(item)}
underline={handleLinkUnderlines(column, item[columnName])}
color={handleLinkColors(column, item[columnName])}
>
{item[columnName] as string}
</Link>
) :
(
<>{column?.needTranslation ? t(item[columnName] as string) : item[columnName]}</>
<>{column?.needTranslation ? t(item[columnName] as string) : item[columnName] as string}</>
)}
</TableCell>
);


Завантаження…
Відмінити
Зберегти