diff --git a/src/app/(main)/invoice/new/page.tsx b/src/app/(main)/invoice/new/page.tsx
index 6ac8255..10e741f 100644
--- a/src/app/(main)/invoice/new/page.tsx
+++ b/src/app/(main)/invoice/new/page.tsx
@@ -1,10 +1,11 @@
import { Metadata } from "next";
-import { getServerI18n } from "@/i18n";
+import { I18nProvider, getServerI18n } from "@/i18n";
import Add from "@mui/icons-material/Add";
import Button from "@mui/material/Button";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import Link from "next/link";
+import CreateInvoice from "@/components/CreateInvoice";
export const metadata: Metadata = {
title: "Create Invoice",
@@ -15,9 +16,10 @@ const Invoice: React.FC = async () => {
return (
<>
-
- {t("Create Invoice")}
-
+ {t("Create Invoice")}
+
+
+
>
)
};
diff --git a/src/app/(main)/invoice/page.tsx b/src/app/(main)/invoice/page.tsx
index d9d18bf..237ca9c 100644
--- a/src/app/(main)/invoice/page.tsx
+++ b/src/app/(main)/invoice/page.tsx
@@ -26,14 +26,14 @@ const Invoice: React.FC = async () => {
{t("Invoice")}
- }
LinkComponent={Link}
href="/invoice/new"
>
{t("Create Invoice")}
-
+ */}
}>
diff --git a/src/app/(main)/settings/position/edit/page.tsx b/src/app/(main)/settings/position/edit/page.tsx
new file mode 100644
index 0000000..0eacb0d
--- /dev/null
+++ b/src/app/(main)/settings/position/edit/page.tsx
@@ -0,0 +1,25 @@
+import EditPosition from "@/components/EditPosition";
+import { I18nProvider, getServerI18n } from "@/i18n";
+import Typography from "@mui/material/Typography";
+import { Metadata } from "next";
+
+export const metadata: Metadata = {
+ title: "Edit Position",
+};
+
+const Positions: React.FC = async () => {
+ const { t } = await getServerI18n("positions");
+
+ // Preload necessary dependencies
+
+ return (
+ <>
+ {t("Edit Position")}
+
+
+
+ >
+ );
+};
+
+export default Positions;
\ No newline at end of file
diff --git a/src/app/api/invoices/actions.ts b/src/app/api/invoices/actions.ts
index c6bdfd2..65778a0 100644
--- a/src/app/api/invoices/actions.ts
+++ b/src/app/api/invoices/actions.ts
@@ -4,32 +4,42 @@ import { serverFetchJson } from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api";
import { cache } from "react";
-
-export interface comboProp {
- id: any;
- label: string;
+export interface InvoiceResult {
+ id: number;
+ projectCode: string;
+ projectName: string;
+ stage: String;
+ comingPaymentMileStone: String;
+ paymentMilestoneDate: String;
+ resourceUsage: number;
+ unbilledHours: number;
+ reminder: String;
}
-export interface combo {
- records: comboProp[];
+export interface CreateInvoiceInputs {
+ id: number;
+ amount: number;
+ billHours: number;
}
-export interface CreateDepartmentInputs {
- departmentCode: string;
- departmentName: string;
- description: string;
+
+export interface InvoiceInformation{
+ id: number;
+ client: string;
+ address: string;
+ attention: string;
+ invoiceDate: string;
+ dueDate: string;
+ projectRefNo: string;
}
-export const saveDepartment = async (data: CreateDepartmentInputs) => {
- return serverFetchJson(`${BASE_API_URL}/departments/new`, {
- method: "POST",
- body: JSON.stringify(data),
- headers: { "Content-Type": "application/json" },
+export const fetchProjectInvoiceById = cache(async (id: number) => {
+ return serverFetchJson(`${BASE_API_URL}/invoices/getProjectDetailById?id=${id}`, {
+ next: { tags: ["projectDetailById"] },
});
- };
+})
-
-export const fetchDepartmentCombo = cache(async () => {
- return serverFetchJson(`${BASE_API_URL}/departments/combo`, {
- next: { tags: ["department"] },
- });
-});
\ No newline at end of file
+export const fetchInvoiceInfoById = cache(async (id: number) => {
+ return serverFetchJson(`${BASE_API_URL}/invoices/getInvoiceInfoById?id=${id}`, {
+ next: { tags: ["invoiceInfoById"] },
+ });
+})
\ No newline at end of file
diff --git a/src/app/api/invoices/index.ts b/src/app/api/invoices/index.ts
index 7c6fb55..9ab55fe 100644
--- a/src/app/api/invoices/index.ts
+++ b/src/app/api/invoices/index.ts
@@ -15,6 +15,15 @@ export interface InvoiceResult {
reminder: String;
}
+export interface InvoiceInformatio{
+ id: number;
+ address: string;
+ attention: string;
+ invoiceDate: string;
+ dueDate: string;
+ projectRefNo: string;
+}
+
export const preloadInvoices = () => {
fetchInvoices();
};
diff --git a/src/app/api/positions/actions.ts b/src/app/api/positions/actions.ts
index e5abc16..2f69990 100644
--- a/src/app/api/positions/actions.ts
+++ b/src/app/api/positions/actions.ts
@@ -3,6 +3,7 @@
import { serverFetchJson } from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api";
import { cache } from "react";
+import { PositionResult } from ".";
export interface comboProp {
id: any;
@@ -19,6 +20,13 @@ export interface CreatePositionInputs {
description: string;
}
+export interface EditPositionInputs {
+ id: number;
+ positionCode: string;
+ positionName: string;
+ description: string;
+}
+
export const savePosition = async (data: CreatePositionInputs) => {
return serverFetchJson(`${BASE_API_URL}/positions/new`, {
method: "POST",
@@ -27,9 +35,22 @@ export const savePosition = async (data: CreatePositionInputs) => {
});
};
-
+ export const editPosition = async (data: EditPositionInputs) => {
+ return serverFetchJson(`${BASE_API_URL}/positions/new`, {
+ method: "POST",
+ body: JSON.stringify(data),
+ headers: { "Content-Type": "application/json" },
+ });
+ };
+
export const fetchPositionCombo = cache(async () => {
return serverFetchJson(`${BASE_API_URL}/positions/combo`, {
next: { tags: ["positions"] },
});
+});
+
+export const fetchPositionDetails = cache(async (id: number) => {
+ return serverFetchJson(`${BASE_API_URL}/positions/${id}`, {
+ next: { tags: ["positionsDetails"] },
+ });
});
\ No newline at end of file
diff --git a/src/app/utils/formatUtil.ts b/src/app/utils/formatUtil.ts
index 14d2ed1..4f364e8 100644
--- a/src/app/utils/formatUtil.ts
+++ b/src/app/utils/formatUtil.ts
@@ -39,7 +39,7 @@ export const shortDateFormatter = (locale?: string) => {
}
};
-export function convertLocaleStringToNumber(numberString: String): number {
+export function convertLocaleStringToNumber(numberString: string): number {
const numberWithoutCommas = numberString.replace(/,/g, "");
return parseFloat(numberWithoutCommas);
}
diff --git a/src/components/CreateInvoice/CreateInvoice.tsx b/src/components/CreateInvoice/CreateInvoice.tsx
new file mode 100644
index 0000000..09c4d2b
--- /dev/null
+++ b/src/components/CreateInvoice/CreateInvoice.tsx
@@ -0,0 +1,142 @@
+"use client";
+import Check from "@mui/icons-material/Check";
+import Close from "@mui/icons-material/Close";
+import Button from "@mui/material/Button";
+import Stack from "@mui/material/Stack";
+import Print from '@mui/icons-material/Print';
+// import { CreateInvoiceInputs, saveInvoice } from "@/app/api/companys/actions";
+import { useRouter } from "next/navigation";
+import React, { useCallback, useState, useLayoutEffect } from "react";
+import { useTranslation } from "react-i18next";
+import {
+ FieldErrors,
+ FormProvider,
+ SubmitErrorHandler,
+ SubmitHandler,
+ useForm,
+ } from "react-hook-form";
+import { useSearchParams } from 'next/navigation'
+import { InvoiceResult } from "@/app/api/invoices";
+import { InvoiceInformation, fetchInvoiceInfoById, fetchProjectInvoiceById } from "@/app/api/invoices/actions";
+import InvoiceDetails from "./InvoiceDetails";
+import ProjectDetails from "./ProjectDetails";
+
+const CreateInvoice: React.FC = ({
+}) => {
+ const { t } = useTranslation();
+ const searchParams = useSearchParams()
+ const router = useRouter()
+
+ const [projectDetail, setProjectDetail] = useState()
+ const [invoiceDetail, setInvoiceDetail] = useState()
+ const [serverError, setServerError] = useState("");
+
+ const fetchProjectDetails = async () =>{
+ const projectId = searchParams.get("id")
+ try{
+ if (projectId !== null && parseInt(projectId) > 0) {
+ const projectDetail = await fetchProjectInvoiceById(parseInt(projectId))
+ console.log(projectDetail)
+ setProjectDetail(projectDetail[0])
+ }
+ } catch (error){
+ console.log(error)
+ setServerError(t("An error has occurred. Please try again later."));
+ }
+ }
+
+ const fetchInvoiceDetails = async () =>{
+ const projectId = searchParams.get("id")
+ try{
+ if (projectId !== null && parseInt(projectId) > 0) {
+ const invoiceInfo = await fetchInvoiceInfoById(parseInt(projectId))
+ console.log(invoiceInfo)
+ setInvoiceDetail(invoiceInfo[0])
+ }
+ } catch (error){
+ console.log(error)
+ setServerError(t("An error has occurred. Please try again later."));
+ }
+ }
+
+ useLayoutEffect(() => {
+ fetchProjectDetails()
+ fetchInvoiceDetails()
+ }, [])
+
+ const handleCancel = () => {
+ router.back();
+ };
+
+ const handlePrintout = () => {
+ console.log("Printing in Progress")
+ }
+
+ const onSubmit = useCallback>(
+ async (data) => {
+ try {
+ console.log(data);
+ setServerError("");
+ // console.log(JSON.stringify(data));
+ // await saveCompany(data)
+ // router.replace("/invoices");
+ } catch (e) {
+ setServerError(t("An error has occurred. Please try again later."));
+ }
+ },
+ [router, t],
+ );
+
+ const onSubmitError = useCallback>(
+ (errors) => {
+ console.log(errors)
+ },
+ [],
+ );
+
+ const formProps = useForm({
+ defaultValues: {
+ },
+ });
+
+ const errors = formProps.formState.errors;
+
+ return(
+
+
+ {
+ projectDetail &&
+ }
+ {
+ invoiceDetail &&
+ }
+
+ }
+ onClick={handleCancel}
+ >
+ {t("Cancel")}
+
+ } type="submit">
+ {t("Confirm")}
+
+ }
+ onClick={handlePrintout}
+ >
+ {t("Generate Print Out")}
+
+
+
+
+ )
+}
+
+export default CreateInvoice;
\ No newline at end of file
diff --git a/src/components/CreateInvoice/CreateInvoiceWrapper.tsx b/src/components/CreateInvoice/CreateInvoiceWrapper.tsx
new file mode 100644
index 0000000..e1f97a0
--- /dev/null
+++ b/src/components/CreateInvoice/CreateInvoiceWrapper.tsx
@@ -0,0 +1,11 @@
+import CreateInvoice from "./CreateInvoice";
+
+const CreateInvoiceWrapper: React.FC = async () => {
+
+ return (
+
+ )
+}
+
+export default CreateInvoiceWrapper;
\ No newline at end of file
diff --git a/src/components/CreateInvoice/InvoiceDetails.tsx b/src/components/CreateInvoice/InvoiceDetails.tsx
new file mode 100644
index 0000000..626ca89
--- /dev/null
+++ b/src/components/CreateInvoice/InvoiceDetails.tsx
@@ -0,0 +1,119 @@
+"use client";
+
+import Stack from "@mui/material/Stack";
+import Box from "@mui/material/Box";
+import Card from "@mui/material/Card";
+import CardContent from "@mui/material/CardContent";
+import FormControl from "@mui/material/FormControl";
+import Grid from "@mui/material/Grid";
+import InputLabel from "@mui/material/InputLabel";
+import MenuItem from "@mui/material/MenuItem";
+import Select from "@mui/material/Select";
+import TextField from "@mui/material/TextField";
+import Typography from "@mui/material/Typography";
+import { useTranslation } from "react-i18next";
+import CardActions from "@mui/material/CardActions";
+import RestartAlt from "@mui/icons-material/RestartAlt";
+import Button from "@mui/material/Button";
+import { Controller, UseFormRegister, useFormContext } from "react-hook-form";
+import { CreateInvoiceInputs } from "@/app/api/invoices/actions";
+import { TimePicker } from "@mui/x-date-pickers";
+import dayjs from 'dayjs';
+import { InvoiceInformation } from "@/app/api/invoices/actions";
+
+interface Props {
+ invoiceinfo: InvoiceInformation
+}
+
+const InvoiceDetails: React.FC = ({
+ invoiceinfo,
+}) => {
+ const { t } = useTranslation();
+ const {
+ register,
+ formState: { errors },
+ control,
+ setValue,
+ getValues,
+ } = useFormContext();
+
+ console.log(invoiceinfo)
+
+ return (
+
+
+
+
+ {t("Invoice Information")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+ }>
+ {t("Reset")}
+
+ */}
+
+
+ );
+};
+
+export default InvoiceDetails;
\ No newline at end of file
diff --git a/src/components/CreateInvoice/ProjectDetails.tsx b/src/components/CreateInvoice/ProjectDetails.tsx
new file mode 100644
index 0000000..f803f72
--- /dev/null
+++ b/src/components/CreateInvoice/ProjectDetails.tsx
@@ -0,0 +1,102 @@
+"use client";
+
+import Stack from "@mui/material/Stack";
+import Box from "@mui/material/Box";
+import Card from "@mui/material/Card";
+import CardContent from "@mui/material/CardContent";
+import FormControl from "@mui/material/FormControl";
+import Grid from "@mui/material/Grid";
+import InputLabel from "@mui/material/InputLabel";
+import MenuItem from "@mui/material/MenuItem";
+import Select from "@mui/material/Select";
+import TextField from "@mui/material/TextField";
+import Typography from "@mui/material/Typography";
+import { useTranslation } from "react-i18next";
+import { InvoiceResult } from "@/app/api/invoices";
+import { useFormContext } from "react-hook-form";
+
+interface Props {
+ projectDetails: InvoiceResult
+}
+
+const ProjectDetails: React.FC = ({
+ projectDetails,
+}) => {
+ const { t } = useTranslation();
+ const {
+ register,
+ formState: { errors },
+ control,
+ setValue,
+ getValues,
+ } = useFormContext();
+
+ return (
+
+
+
+
+ {t("Project Details")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+ }>
+ {t("Reset")}
+
+ */}
+
+
+ );
+};
+
+export default ProjectDetails;
\ No newline at end of file
diff --git a/src/components/CreateInvoice/index.ts b/src/components/CreateInvoice/index.ts
new file mode 100644
index 0000000..74f78fc
--- /dev/null
+++ b/src/components/CreateInvoice/index.ts
@@ -0,0 +1 @@
+export { default } from "./CreateInvoiceWrapper"
diff --git a/src/components/CreateProject/CreateProject.tsx b/src/components/CreateProject/CreateProject.tsx
index 61409b0..b8faa5e 100644
--- a/src/components/CreateProject/CreateProject.tsx
+++ b/src/components/CreateProject/CreateProject.tsx
@@ -61,7 +61,9 @@ const hasErrorsInTab = (
) => {
switch (tabIndex) {
case 0:
- return errors.projectName;
+ return (
+ errors.projectName || errors.projectCode || errors.projectDescription
+ );
default:
false;
}
@@ -101,7 +103,6 @@ const CreateProject: React.FC = ({
const onSubmit = useCallback>(
async (data) => {
try {
- console.log(data);
setServerError("");
await saveProject(data);
router.replace("/projects");
@@ -115,7 +116,11 @@ const CreateProject: React.FC = ({
const onSubmitError = useCallback>(
(errors) => {
// Set the tab so that the focus will go there
- if (errors.projectName) {
+ if (
+ errors.projectName ||
+ errors.projectDescription ||
+ errors.projectCode
+ ) {
setTabIndex(0);
}
},
diff --git a/src/components/CreateProject/MilestoneSection.tsx b/src/components/CreateProject/MilestoneSection.tsx
index 9d18717..68a35a2 100644
--- a/src/components/CreateProject/MilestoneSection.tsx
+++ b/src/components/CreateProject/MilestoneSection.tsx
@@ -29,7 +29,7 @@ import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next";
import StyledDataGrid from "../StyledDataGrid";
-import { moneyFormatter } from "@/app/utils/formatUtil";
+import { INPUT_DATE_FORMAT, moneyFormatter } from "@/app/utils/formatUtil";
import isDate from "lodash/isDate";
interface Props {
@@ -206,7 +206,7 @@ const MilestoneSection: React.FC = ({ taskGroupId }) => {
description: p.description!,
id: p.id!,
amount: p.amount!,
- date: dayjs(p.date!).toISOString(),
+ date: dayjs(p.date!).format(INPUT_DATE_FORMAT),
})),
},
});
@@ -245,7 +245,7 @@ const MilestoneSection: React.FC = ({ taskGroupId }) => {
...milestones,
[taskGroupId]: {
...milestones[taskGroupId],
- startDate: date.toISOString(),
+ startDate: date.format(INPUT_DATE_FORMAT),
},
});
}}
@@ -264,7 +264,7 @@ const MilestoneSection: React.FC = ({ taskGroupId }) => {
...milestones,
[taskGroupId]: {
...milestones[taskGroupId],
- endDate: date.toISOString(),
+ endDate: date.format(INPUT_DATE_FORMAT),
},
});
}}
diff --git a/src/components/EditPosition/EditPosition.tsx b/src/components/EditPosition/EditPosition.tsx
new file mode 100644
index 0000000..92cf871
--- /dev/null
+++ b/src/components/EditPosition/EditPosition.tsx
@@ -0,0 +1,144 @@
+"use client";
+
+import Check from "@mui/icons-material/Check";
+import Close from "@mui/icons-material/Close";
+import Button 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 React, { useCallback, useState, useLayoutEffect, useEffect } from "react";
+import { useTranslation } from "react-i18next";
+import { Task, TaskTemplate } from "@/app/api/tasks";
+import {
+ FieldErrors,
+ FormProvider,
+ SubmitErrorHandler,
+ SubmitHandler,
+ useForm,
+} from "react-hook-form";
+import { EditPositionInputs, editPosition, fetchPositionDetails, savePosition } from "@/app/api/positions/actions";
+import { Error } from "@mui/icons-material";
+import { ProjectCategory } from "@/app/api/projects";
+import { Typography } from "@mui/material";
+import PositionDetails from "./PositionDetails";
+import { useSearchParams } from 'next/navigation'
+import { PositionResult } from "@/app/api/positions";
+
+
+const EditPosition: React.FC = ({
+ // allTasks,
+ // projectCategories,
+ // taskTemplates,
+ // teamLeads,
+}) => {
+ const [serverError, setServerError] = useState("");
+ const { t } = useTranslation();
+ const searchParams = useSearchParams()
+ const router = useRouter();
+
+ const [positionDetails, setPositionDetails] = useState()
+ const positionId = searchParams.get("id")
+
+ const fetchPositionDetail = async () =>{
+ console.log(positionId)
+ try{
+ if (positionId !== null && parseInt(positionId) > 0) {
+ const postionDetails = await fetchPositionDetails(parseInt(positionId))
+ const updatedArray: EditPositionInputs[] = postionDetails.map((obj) => {
+ return {
+ id: obj.id,
+ positionCode: obj.code,
+ positionName: obj.name,
+ description: obj.description
+ };
+ });
+
+ setPositionDetails(updatedArray[0])
+ }
+ } catch (error){
+ console.log(error)
+ setServerError(t("An error has occurred. Please try again later."));
+ }
+ }
+
+ const handleCancel = () => {
+ router.back();
+ };
+
+ const onSubmit = useCallback>(
+ async (data) => {
+ try {
+ if (positionId !== null && parseInt(positionId) > 0) {
+ console.log(data);
+ setServerError("");
+ // console.log(JSON.stringify(data));
+ data.id = parseInt(positionId)
+ console.log(data);
+ await editPosition(data)
+ router.replace("/settings/position");
+ }
+ } catch (e) {
+ setServerError(t("An error has occurred. Please try again later."));
+ }
+ },
+ [router, t],
+ );
+
+ const onSubmitError = useCallback>(
+ (errors) => {
+ console.log(errors)
+ },
+ [],
+ );
+
+ const formProps = useForm({
+ // defaultValues: {
+ // positionCode: positionDetails ? positionDetails.code : "AAA",
+ // positionName: positionDetails ? positionDetails.name : "BBB",
+ // description: positionDetails ? positionDetails.description : "CCC",
+ // },
+ });
+
+ const errors = formProps.formState.errors;
+
+ useEffect(() => {
+ fetchPositionDetail()
+ }, [])
+
+ useEffect(() => {
+ if (positionDetails !== null && positionDetails !== undefined) {
+ console.log(positionDetails)
+
+ formProps.reset(positionDetails)
+ }
+ }, [positionDetails])
+
+ return (
+
+
+ {
+ positionDetails &&
+ }
+
+ }
+ onClick={handleCancel}
+ >
+ {t("Cancel")}
+
+ } type="submit">
+ {t("Confirm")}
+
+
+
+
+ );
+};
+
+export default EditPosition;
diff --git a/src/components/EditPosition/EditPositionWrapper.tsx b/src/components/EditPosition/EditPositionWrapper.tsx
new file mode 100644
index 0000000..dc531ee
--- /dev/null
+++ b/src/components/EditPosition/EditPositionWrapper.tsx
@@ -0,0 +1,18 @@
+import EditPosition from "./EditPosition";
+
+const EditPositionWrapper: React.FC = async () => {
+ // const [tasks, taskTemplates, PositionCategories, teamLeads] =
+ // await Promise.all([
+ // fetchAllTasks(),
+ // fetchTaskTemplates(),
+ // fetchPositionCategories(),
+ // fetchTeamLeads(),
+ // ]);
+
+ return (
+
+ );
+};
+
+export default EditPositionWrapper;
diff --git a/src/components/EditPosition/PositionDetails.tsx b/src/components/EditPosition/PositionDetails.tsx
new file mode 100644
index 0000000..086998e
--- /dev/null
+++ b/src/components/EditPosition/PositionDetails.tsx
@@ -0,0 +1,87 @@
+"use client";
+
+import Stack from "@mui/material/Stack";
+import Box from "@mui/material/Box";
+import Card from "@mui/material/Card";
+import CardContent from "@mui/material/CardContent";
+import FormControl from "@mui/material/FormControl";
+import Grid from "@mui/material/Grid";
+import InputLabel from "@mui/material/InputLabel";
+import MenuItem from "@mui/material/MenuItem";
+import Select from "@mui/material/Select";
+import TextField from "@mui/material/TextField";
+import Typography from "@mui/material/Typography";
+import { useTranslation } from "react-i18next";
+import CardActions from "@mui/material/CardActions";
+import RestartAlt from "@mui/icons-material/RestartAlt";
+import Button from "@mui/material/Button";
+import { Controller, useFormContext } from "react-hook-form";
+import { EditPositionInputs } from "@/app/api/positions/actions";
+import { PositionResult } from "@/app/api/positions";
+import { useEffect } from "react";
+
+interface Props {
+ positionDetails: EditPositionInputs
+}
+const PositionDetails: React.FC = ({
+ positionDetails,
+}) => {
+ const { t } = useTranslation();
+ const {
+ register,
+ formState: { errors },
+ control,
+ setValue,
+ } = useFormContext();
+
+ return (
+
+
+
+
+ {t("Position Details")}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/*
+ }>
+ {t("Reset")}
+
+ */}
+
+
+ );
+};
+
+export default PositionDetails;
\ No newline at end of file
diff --git a/src/components/EditPosition/index.ts b/src/components/EditPosition/index.ts
new file mode 100644
index 0000000..d6ccc4f
--- /dev/null
+++ b/src/components/EditPosition/index.ts
@@ -0,0 +1 @@
+export { default } from "./EditPositionWrapper"
\ No newline at end of file
diff --git a/src/components/InvoiceSearch/InvoiceSearch.tsx b/src/components/InvoiceSearch/InvoiceSearch.tsx
index 56b6204..52dbdd5 100644
--- a/src/components/InvoiceSearch/InvoiceSearch.tsx
+++ b/src/components/InvoiceSearch/InvoiceSearch.tsx
@@ -6,6 +6,7 @@ import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults";
import EditNote from "@mui/icons-material/EditNote";
import { InvoiceResult } from "@/app/api/invoices";
+import { useRouter } from "next/navigation";
interface Props {
invoices: InvoiceResult[];
@@ -16,6 +17,7 @@ type SearchParamNames = keyof SearchQuery;
const InvoiceSearch: React.FC = ({ invoices }) => {
const { t } = useTranslation("invoices");
+ const router = useRouter();
const [filteredInvoices, setFilteredInvoices] = useState(invoices);
@@ -24,8 +26,18 @@ const InvoiceSearch: React.FC = ({ invoices }) => {
{ label: t("Project code"), paramName: "projectCode", type: "text" },
{ label: t("Project name"), paramName: "projectName", type: "text" },
// { label: t("Stage"), paramName: "stage", type: "text" },
- { label: t("Coming payment milestone"), paramName: "comingPaymentMileStone", type: "text" },
- { label: t("Payment date"), paramName: "paymentMilestoneDate", type: "text" },
+ {
+ label: t("Coming payment milestone from"),
+ label2: t("Coming payment milestone to"),
+ paramName: "comingPaymentMileStone",
+ type: "dateRange"
+ },
+ {
+ label: t("Payment date from"),
+ label2: t("Payment date to"),
+ paramName: "paymentMilestoneDate",
+ type: "dateRange"
+ },
// { label: t("Resource utilization %"), paramName: "resourceUsage", type: "text" },
// { label: t("Unbilled hours"), paramName: "unbilledHours", type: "text" },
// { label: t("Reminder to issue invoice"), paramName: "reminder", type: "text" },
@@ -39,7 +51,8 @@ const InvoiceSearch: React.FC = ({ invoices }) => {
const onProjectClick = useCallback((project: InvoiceResult) => {
console.log(project);
- }, []);
+ router.push(`/invoice/new?id=${project.id}`)
+ }, [router, t]);
const columns = useMemo[]>(
() => [
@@ -66,12 +79,12 @@ const InvoiceSearch: React.FC = ({ invoices }) => {
{
+ console.log(query)
setFilteredInvoices(
invoices.filter(
(d) =>
d.projectCode.toLowerCase().includes(query.projectCode.toLowerCase()) &&
d.projectName.toLowerCase().includes(query.projectName.toLowerCase()) &&
- d.stage.toLowerCase().includes(query.stage.toLowerCase()) &&
{/*(query.client === "All" || p.client === query.client) &&
(query.category === "All" || p.category === query.category) &&
(query.team === "All" || p.team === query.team), **/}
diff --git a/src/components/InvoiceSearch/InvoiceSearchWrapper.tsx b/src/components/InvoiceSearch/InvoiceSearchWrapper.tsx
index 4312fb9..420736f 100644
--- a/src/components/InvoiceSearch/InvoiceSearchWrapper.tsx
+++ b/src/components/InvoiceSearch/InvoiceSearchWrapper.tsx
@@ -2,7 +2,6 @@
import React from "react";
import InvoiceSearch from "./InvoiceSearch";
import InvoiceSearchLoading from "./InvoiceSearchLoading";
-// For Later use
import { fetchInvoices } from "@/app/api/invoices";
interface SubComponents {
@@ -10,7 +9,6 @@ interface SubComponents {
}
const InvoiceSearchWrapper: React.FC & SubComponents = async () => {
- // For Later use
const Invoices = await fetchInvoices();
return ;
diff --git a/src/components/PositionSearch/PositionSearch.tsx b/src/components/PositionSearch/PositionSearch.tsx
index bd3cc4e..d0b3ee4 100644
--- a/src/components/PositionSearch/PositionSearch.tsx
+++ b/src/components/PositionSearch/PositionSearch.tsx
@@ -6,6 +6,7 @@ import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults";
import EditNote from "@mui/icons-material/EditNote";
import { PositionResult } from "@/app/api/positions";
+import { useRouter } from "next/navigation";
interface Props {
positions: PositionResult[];
@@ -16,6 +17,7 @@ type SearchParamNames = keyof SearchQuery;
const PositionSearch: React.FC = ({ positions }) => {
const { t } = useTranslation("positions");
+ const router = useRouter();
const [filteredPositions, setFilteredPositions] = useState(positions);
@@ -32,8 +34,10 @@ const PositionSearch: React.FC = ({ positions }) => {
setFilteredPositions(positions);
}, [positions]);
- const onProjectClick = useCallback((project: PositionResult) => {
+ const onPositionClick = useCallback((project: PositionResult) => {
console.log(project);
+ const id = project.id
+ router.push(`/settings/position/edit?id=${id}`);
}, []);
const columns = useMemo[]>(
@@ -41,14 +45,14 @@ const PositionSearch: React.FC = ({ positions }) => {
{
name: "id",
label: t("Details"),
- onClick: onProjectClick,
+ onClick: onPositionClick,
buttonIcon: ,
},
{ name: "code", label: t("Position Code") },
{ name: "name", label: t("Position Name") },
{ name: "description", label: t("Position Description") },
],
- [t, onProjectClick],
+ [t, onPositionClick],
);
return (
diff --git a/src/components/TimesheetTable/EntryInputTable.tsx b/src/components/TimesheetTable/EntryInputTable.tsx
index 57a18b3..7d9e9de 100644
--- a/src/components/TimesheetTable/EntryInputTable.tsx
+++ b/src/components/TimesheetTable/EntryInputTable.tsx
@@ -22,6 +22,9 @@ import { AssignedProject } from "@/app/api/projects";
import uniqBy from "lodash/uniqBy";
import { TaskGroup } from "@/app/api/tasks";
import dayjs from "dayjs";
+import isBetween from "dayjs/plugin/isBetween";
+
+dayjs.extend(isBetween);
const mockProjects: AssignedProject[] = [
{