Bladeren bron

Add not-found page for edit project

tags/Baseline_30082024_FRONTEND_UAT
Wayne 1 jaar geleden
bovenliggende
commit
966d7d0c65
6 gewijzigde bestanden met toevoegingen van 68 en 15 verwijderingen
  1. +17
    -0
      src/app/(main)/projects/edit/not-found.tsx
  2. +19
    -7
      src/app/(main)/projects/edit/page.tsx
  3. +14
    -1
      src/app/utils/fetchUtil.ts
  4. +1
    -0
      src/components/Breadcrumb/Breadcrumb.tsx
  5. +16
    -6
      src/components/CreateProject/CreateProject.tsx
  6. +1
    -1
      src/components/ProjectSearch/ProjectSearch.tsx

+ 17
- 0
src/app/(main)/projects/edit/not-found.tsx Bestand weergeven

@@ -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("projects", "common");

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

src/app/(main)/projects/edit/[projectId]/page.tsx → src/app/(main)/projects/edit/page.tsx Bestand weergeven

@@ -12,23 +12,30 @@ import {
} from "@/app/api/projects";
import { preloadStaff, preloadTeamLeads } from "@/app/api/staff";
import { fetchAllTasks, fetchTaskTemplates } from "@/app/api/tasks";
import { ServerFetchError } from "@/app/utils/fetchUtil";
import CreateProject from "@/components/CreateProject";
import { I18nProvider, getServerI18n } from "@/i18n";
import Typography from "@mui/material/Typography";
import { isArray } from "lodash";
import { Metadata } from "next";
import { notFound } from "next/navigation";

interface Props {
params: {
projectId: string;
};
searchParams: { [key: string]: string | string[] | undefined };
}

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

const Projects: React.FC<Props> = async ({ params }) => {
const Projects: React.FC<Props> = async ({ searchParams }) => {
const { t } = await getServerI18n("projects");
// Assume projectId is string here
const projectId = searchParams["id"];

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

// Preload necessary dependencies
fetchAllTasks();
@@ -46,14 +53,19 @@ const Projects: React.FC<Props> = async ({ params }) => {
preloadTeamLeads();
preloadStaff();

// TODO: Handle not found
const fetchedProject = await fetchProjectDetails(params.projectId);
try {
await fetchProjectDetails(projectId);
} catch (e) {
if (e instanceof ServerFetchError && e.response?.status === 404) {
notFound();
}
}

return (
<>
<Typography variant="h4">{t("Edit Project")}</Typography>
<I18nProvider namespaces={["projects"]}>
<CreateProject isEditMode projectId={params.projectId} />
<CreateProject isEditMode projectId={projectId} />
</I18nProvider>
</>
);

+ 14
- 1
src/app/utils/fetchUtil.ts Bestand weergeven

@@ -3,6 +3,16 @@ import { getServerSession } from "next-auth";
import { headers } from "next/headers";
import { redirect } from "next/navigation";

export class ServerFetchError extends Error {
public readonly response: Response | undefined;
constructor(message?: string, response?: Response) {
super(message);
this.response = response;

Object.setPrototypeOf(this, ServerFetchError.prototype);
}
}

export const serverFetch: typeof fetch = async (input, init) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const session = await getServerSession<any, SessionWithTokens>(authOptions);
@@ -37,7 +47,10 @@ export async function serverFetchJson<T>(...args: FetchParams) {
signOutUser();
default:
console.error(await response.text());
throw Error("Something went wrong fetching data in server.");
throw new ServerFetchError(
"Something went wrong fetching data in server.",
response,
);
}
}
}


+ 1
- 0
src/components/Breadcrumb/Breadcrumb.tsx Bestand weergeven

@@ -12,6 +12,7 @@ const pathToLabelMap: { [path: string]: string } = {
"/home": "User Workspace",
"/projects": "Projects",
"/projects/create": "Create Project",
"/projects/edit": "Edit Project",
"/tasks": "Task Template",
"/tasks/create": "Create Task Template",
"/staffReimbursement": "Staff Reimbursement",


+ 16
- 6
src/components/CreateProject/CreateProject.tsx Bestand weergeven

@@ -36,6 +36,7 @@ import { StaffResult } from "@/app/api/staff";
import { Typography } from "@mui/material";
import { Grade } from "@/app/api/grades";
import { Customer, Subsidiary } from "@/app/api/customer";
import { isEmpty } from "lodash";

export interface Props {
isEditMode: boolean;
@@ -108,13 +109,17 @@ const CreateProject: React.FC<Props> = ({
async (data) => {
try {
setServerError("");
await saveProject(data);
if (isEditMode) {
console.log("edit project", data);
} else {
await saveProject(data);
}
router.replace("/projects");
} catch (e) {
setServerError(t("An error has occurred. Please try again later."));
}
},
[router, t],
[router, t, isEditMode],
);

const onSubmitError = useCallback<SubmitErrorHandler<CreateProjectInputs>>(
@@ -132,14 +137,19 @@ const CreateProject: React.FC<Props> = ({
);

const formProps = useForm<CreateProjectInputs>({
defaultValues: defaultInputs ?? {
defaultValues: {
taskGroups: {},
allocatedStaffIds: [],
milestones: {},
totalManhour: 0,
manhourPercentageByGrade: grades.reduce((acc, grade) => {
return { ...acc, [grade.id]: 1 / grades.length };
}, {}),
...defaultInputs,

// manhourPercentageByGrade should have a sensible default
manhourPercentageByGrade: isEmpty(defaultInputs?.manhourPercentageByGrade)
? grades.reduce((acc, grade) => {
return { ...acc, [grade.id]: 1 / grades.length };
}, {})
: defaultInputs.manhourPercentageByGrade,
},
});



+ 1
- 1
src/components/ProjectSearch/ProjectSearch.tsx Bestand weergeven

@@ -55,7 +55,7 @@ const ProjectSearch: React.FC<Props> = ({ projects, projectCategories }) => {

const onProjectClick = useCallback(
(project: ProjectResult) => {
router.push(`/projects/edit/${project.id}`);
router.push(`/projects/edit?id=${project.id}`);
},
[router],
);


Laden…
Annuleren
Opslaan