Преглед на файлове

update task template

tags/Baseline_30082024_FRONTEND_UAT
cyril.tsui преди 1 година
родител
ревизия
ffcaf32efa
променени са 7 файла, в които са добавени 126 реда и са изтрити 48 реда
  1. +17
    -0
      src/app/(main)/tasks/edit/not-found.tsx
  2. +24
    -3
      src/app/(main)/tasks/edit/page.tsx
  3. +13
    -0
      src/app/api/tasks/actions.ts
  4. +12
    -0
      src/app/api/tasks/index.ts
  5. +42
    -38
      src/components/CreateTaskTemplate/CreateTaskTemplate.tsx
  6. +11
    -4
      src/components/CreateTaskTemplate/CreateTaskTemplateWrapper.tsx
  7. +7
    -3
      src/components/Swal/CustomAlerts.js

+ 17
- 0
src/app/(main)/tasks/edit/not-found.tsx Целия файл

@@ -0,0 +1,17 @@
import { getServerI18n } from "@/i18n";
import { Stack, Typography, Link } from "@mui/material";
import NextLink from "next/link";

export default async function NotFound() {
const { t } = await getServerI18n("tasks", "common");

return (
<Stack spacing={2}>
<Typography variant="h4">{t("Not Found")}</Typography>
<Typography variant="body1">{t("The task template was not found!")}</Typography>
<Link href="/projects" component={NextLink} variant="body2">
{t("Return to all task templates")}
</Link>
</Stack>
);
}

+ 24
- 3
src/app/(main)/tasks/edit/page.tsx Целия файл

@@ -1,23 +1,44 @@
import { preloadAllTasks } from "@/app/api/tasks";
import { fetchTaskTemplate, preloadAllTasks } from "@/app/api/tasks";
import CreateTaskTemplate from "@/components/CreateTaskTemplate";
import { getServerI18n } from "@/i18n";
import Typography from "@mui/material/Typography";
import { Metadata } from "next";
import { I18nProvider } from "@/i18n";
import { ServerFetchError } from "@/app/utils/fetchUtil";
import { isArray } from "lodash";
import { notFound } from "next/navigation";

export const metadata: Metadata = {
title: "Edit Task Template",
};

const TaskTemplates: React.FC = async () => {
interface Props {
searchParams: { [key: string]: string | string[] | undefined };
}

const TaskTemplates: React.FC<Props> = async ({ searchParams }) => {
const { t } = await getServerI18n("tasks");
const taskTemplateId = searchParams["id"];

if (!taskTemplateId || isArray(taskTemplateId)) {
notFound();
}

preloadAllTasks();

try {
await fetchTaskTemplate(taskTemplateId);
} catch (e) {
if (e instanceof ServerFetchError && e.response?.status === 404) {
notFound();
}
}

return (
<>
<Typography variant="h4">{t("Edit Task Template")}</Typography>
<I18nProvider namespaces={["tasks", "common"]}>
<CreateTaskTemplate />
<CreateTaskTemplate taskTemplateId={taskTemplateId}/>
</I18nProvider>
</>
);


+ 13
- 0
src/app/api/tasks/actions.ts Целия файл

@@ -4,13 +4,26 @@ import { serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil
import { BASE_API_URL } from "@/config/api";
import { TaskTemplate } from ".";
import { revalidateTag } from "next/cache";
import { ManhourAllocation } from "@/app/api/projects/actions";
import { Task, TaskGroup } from '@/app/api/tasks';

export interface NewTaskTemplateFormInputs {

// task template
code: string;
name: string;
taskIds: number[];

id: number | null;

// resource allocation template
manhourPercentageByGrade: ManhourAllocation;
taskGroups: {
[taskGroup: TaskGroup["id"]]: {
taskIds: Task["id"][];
percentAllocation: number;
};
};
}

export const saveTaskTemplate = async (data: NewTaskTemplateFormInputs) => {


+ 12
- 0
src/app/api/tasks/index.ts Целия файл

@@ -39,3 +39,15 @@ export const preloadAllTasks = () => {
export const fetchAllTasks = cache(async () => {
return serverFetchJson<Task[]>(`${BASE_API_URL}/tasks`);
});

export const fetchTaskTemplate = cache(async (id: string) => {
const taskTemplate = await serverFetchJson<TaskTemplate>(
`${BASE_API_URL}/tasks/templatesDetails/${id}`,
{
method: "GET",
headers: { "Content-Type": "application/json" },
},
);

return taskTemplate;
});

+ 42
- 38
src/components/CreateTaskTemplate/CreateTaskTemplate.tsx Целия файл

@@ -13,7 +13,7 @@ import Close from "@mui/icons-material/Close";
import { useRouter, useSearchParams } from "next/navigation";
import React from "react";
import Stack from "@mui/material/Stack";
import { Task } from "@/app/api/tasks";
import { Task, TaskTemplate } from "@/app/api/tasks";
import {
NewTaskTemplateFormInputs,
fetchTaskTemplate,
@@ -24,9 +24,10 @@ import { errorDialog, submitDialog, successDialog } from "../Swal/CustomAlerts";

interface Props {
tasks: Task[];
defaultInputs?: TaskTemplate;
}

const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => {
const CreateTaskTemplate: React.FC<Props> = ({ tasks, defaultInputs }) => {
const { t } = useTranslation();

const searchParams = useSearchParams()
@@ -54,45 +55,45 @@ const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => {
watch,
resetField,
formState: { errors, isSubmitting },
} = useForm<NewTaskTemplateFormInputs>({ defaultValues: { taskIds: [] } });
} = useForm<NewTaskTemplateFormInputs>({ defaultValues: defaultInputs });

const currentTaskIds = watch("taskIds");
const selectedItems = React.useMemo(() => {
return items.filter((item) => currentTaskIds.includes(item.id));
}, [currentTaskIds, items]);

const [refTaskTemplate, setRefTaskTemplate] = React.useState<NewTaskTemplateFormInputs>()
const id = searchParams.get('id')
const fetchCurrentTaskTemplate = async () => {
try {
const taskTemplate = await fetchTaskTemplate(parseInt(id!!))
const defaultValues = {
id: parseInt(id!!),
code: taskTemplate.code ?? null,
name: taskTemplate.name ?? null,
taskIds: taskTemplate.tasks.map(task => task.id) ?? [],
}
setRefTaskTemplate(defaultValues)
} catch (e) {
console.log(e)
}
}
React.useLayoutEffect(() => {
if (id !== null && parseInt(id) > 0) fetchCurrentTaskTemplate()
}, [id])
React.useEffect(() => {
if (refTaskTemplate) {
setValue("taskIds", refTaskTemplate.taskIds)
resetField("code", { defaultValue: refTaskTemplate.code })
resetField("name", { defaultValue: refTaskTemplate.name })
setValue("id", refTaskTemplate.id)
}
}, [refTaskTemplate])
// const [refTaskTemplate, setRefTaskTemplate] = React.useState<NewTaskTemplateFormInputs>()
// const id = searchParams.get('id')
// const fetchCurrentTaskTemplate = async () => {
// try {
// const taskTemplate = await fetchTaskTemplate(parseInt(id!!))
// const defaultValues = {
// id: parseInt(id!!),
// code: taskTemplate.code ?? null,
// name: taskTemplate.name ?? null,
// taskIds: taskTemplate.tasks.map(task => task.id) ?? [],
// }
// setRefTaskTemplate(defaultValues)
// } catch (e) {
// console.log(e)
// }
// }
// React.useLayoutEffect(() => {
// if (id !== null && parseInt(id) > 0) fetchCurrentTaskTemplate()
// }, [id])
// React.useEffect(() => {
// if (refTaskTemplate) {
// setValue("taskIds", refTaskTemplate.taskIds)
// resetField("code", { defaultValue: refTaskTemplate.code })
// resetField("name", { defaultValue: refTaskTemplate.name })
// setValue("id", refTaskTemplate.id)
// }
// }, [refTaskTemplate])

const onSubmit: SubmitHandler<NewTaskTemplateFormInputs> = React.useCallback(
async (data) => {
@@ -120,9 +121,9 @@ const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => {

return (
<>
{
(id === null || refTaskTemplate !== undefined) && <Stack component="form" onSubmit={handleSubmit(onSubmit)} gap={2}>
<Stack component="form" onSubmit={handleSubmit(onSubmit)} gap={2}>
<Card>
{/* Task List Setup */}
<CardContent sx={{ display: "flex", flexDirection: "column", gap: 1 }}>
<Typography variant="overline">{t("Task List Setup")}</Typography>
<Grid
@@ -166,6 +167,9 @@ const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => {
allItemsLabel={t("Task Pool")}
selectedItemsLabel={t("Task List Template")}
/>
{/* Task List Setup */}
{/* Task List Setup */}

</CardContent>
</Card>
{
@@ -188,7 +192,7 @@ const CreateTaskTemplate: React.FC<Props> = ({ tasks }) => {
{t("Confirm")}
</Button>
</Stack>
</Stack >}
</Stack >
</>
);
};


+ 11
- 4
src/components/CreateTaskTemplate/CreateTaskTemplateWrapper.tsx Целия файл

@@ -1,11 +1,18 @@
import React from "react";
import CreateTaskTemplate from "./CreateTaskTemplate";
import { fetchAllTasks } from "@/app/api/tasks";
import { fetchAllTasks, fetchTaskTemplate } from "@/app/api/tasks";

const CreateTaskTemplateWrapper: React.FC = async () => {
const tasks = await fetchAllTasks();
interface Props {
taskTemplateId?: string;
}

return <CreateTaskTemplate tasks={tasks} />;
const CreateTaskTemplateWrapper: React.FC<Props> = async (props) => {
const [tasks] = await Promise.all([
fetchAllTasks(),
]);

const taskTemplateInfo = props.taskTemplateId ? await fetchTaskTemplate(props.taskTemplateId) : undefined
return <CreateTaskTemplate tasks={tasks} defaultInputs={taskTemplateInfo}/>;
};

export default CreateTaskTemplateWrapper;

+ 7
- 3
src/components/Swal/CustomAlerts.js Целия файл

@@ -51,13 +51,17 @@ export const warningDialog = (text, t) => {
})
}

export const submitDialog = async (confirmAction, t, {...props}) => {
export const submitDialog = async (confirmAction, t, {...props} = {
title: null,
confirmButtonText: null
}) => {
// console.log(props)
// const { t } = useTranslation("common")
const result = await Swal.fire({
icon: "question",
title: props.title ?? t("Do you want to submit?"),
title: props?.title ?? t("Do you want to submit?"),
cancelButtonText: t("Cancel"),
confirmButtonText: props.confirmButtonText ?? t("Submit"),
confirmButtonText: props?.confirmButtonText ?? t("Submit"),
showCancelButton: true,
showConfirmButton: true,
customClass: {


Зареждане…
Отказ
Запис