Browse Source

update

tags/Baseline_30082024_FRONTEND_UAT
cyril.tsui 1 year ago
parent
commit
f0db5eae76
9 changed files with 32 additions and 14 deletions
  1. +3
    -4
      src/app/api/customer/actions.ts
  2. +3
    -1
      src/app/api/customer/index.ts
  3. +2
    -0
      src/app/api/subsidiary/actions.ts
  4. +1
    -1
      src/app/api/subsidiary/index.ts
  5. +4
    -3
      src/components/CustomerSearch/CustomerSearch.tsx
  6. +1
    -1
      src/components/CustomerSearch/CustomerSearchWrapper.tsx
  7. +9
    -2
      src/components/NavigationContent/NavigationContent.tsx
  8. +6
    -2
      src/components/SubsidiarySearch/SubsidiarySearch.tsx
  9. +3
    -0
      src/middleware.ts

+ 3
- 4
src/app/api/customer/actions.ts View File

@@ -1,11 +1,9 @@
import { Subsidiary } from '@/app/api/customer';
"use server"; "use server";


import { serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil"; import { serverFetchJson, serverFetchWithNoContent } from "@/app/utils/fetchUtil";
import { BASE_API_URL } from "@/config/api"; import { BASE_API_URL } from "@/config/api";
import { Contact, Customer, SaveCustomerResponse } from "."; import { Contact, Customer, SaveCustomerResponse } from ".";
import { revalidateTag } from "next/cache";
import { cache } from "react";
import { revalidatePath, revalidateTag } from "next/cache";




export interface CustomerFormInputs { export interface CustomerFormInputs {
@@ -72,6 +70,7 @@ export const deleteCustomer = async (id: number) => {
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
}, },
); );

revalidateTag("customers")
return customer return customer
}; };

+ 3
- 1
src/app/api/customer/index.ts View File

@@ -72,7 +72,9 @@ export const preloadAllCustomers = () => {
}; };


export const fetchAllCustomers = cache(async () => { export const fetchAllCustomers = cache(async () => {
return serverFetchJson<Customer[]>(`${BASE_API_URL}/customer`);
return serverFetchJson<Customer[]>(`${BASE_API_URL}/customer`, {
next: { tags: ["customers"]}
});
}); });


export const fetchAllSubsidiaries = cache(async () => { export const fetchAllSubsidiaries = cache(async () => {


+ 2
- 0
src/app/api/subsidiary/actions.ts View File

@@ -70,5 +70,7 @@ export const deleteSubsidiary = async (id: number) => {
}, },
); );


revalidateTag("subsidiaries");

return subsidiary return subsidiary
}; };

+ 1
- 1
src/app/api/subsidiary/index.ts View File

@@ -74,7 +74,7 @@ export const fetchAllSubsidiaries = cache(async () => {
return serverFetchJson<Subsidiary[]>( return serverFetchJson<Subsidiary[]>(
`${BASE_API_URL}/subsidiary`, `${BASE_API_URL}/subsidiary`,
{ {
next: { tags: ["subsidiary"] },
next: { tags: ["subsidiaries"] },
}, },
); );
}); });


+ 4
- 3
src/components/CustomerSearch/CustomerSearch.tsx View File

@@ -1,7 +1,7 @@
"use client"; "use client";


import { Customer } from "@/app/api/customer"; import { Customer } from "@/app/api/customer";
import React, { useCallback, useMemo, useState } from "react";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import SearchBox, { Criterion } from "../SearchBox"; import SearchBox, { Criterion } from "../SearchBox";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults"; import SearchResults, { Column } from "../SearchResults";
@@ -24,6 +24,9 @@ const CustomerSearch: React.FC<Props> = ({ customers }) => {
const searchParams = useSearchParams() const searchParams = useSearchParams()


const [filteredCustomers, setFilteredCustomers] = useState(customers); const [filteredCustomers, setFilteredCustomers] = useState(customers);
useEffect(() => {
setFilteredCustomers(customers)
}, [customers])
const searchCriteria: Criterion<SearchParamNames>[] = useMemo( const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [ () => [
{ label: t("Customer Code"), paramName: "code", type: "text" }, { label: t("Customer Code"), paramName: "code", type: "text" },
@@ -47,8 +50,6 @@ const CustomerSearch: React.FC<Props> = ({ customers }) => {
await deleteCustomer(customer.id) await deleteCustomer(customer.id)


successDialog("Delete Success", t) successDialog("Delete Success", t)

setFilteredCustomers((prev) => prev.filter((obj) => obj.id !== customer.id))
}, t) }, t)
}, []); }, []);




+ 1
- 1
src/components/CustomerSearch/CustomerSearchWrapper.tsx View File

@@ -8,7 +8,7 @@ interface SubComponents {
} }


const CustomerSearchWrapper: React.FC & SubComponents = async () => { const CustomerSearchWrapper: React.FC & SubComponents = async () => {
const customers = await fetchAllCustomers();
const [customers] = await Promise.all([fetchAllCustomers()]);


return <CustomerSearch customers={customers} />; return <CustomerSearch customers={customers} />;
}; };


+ 9
- 2
src/components/NavigationContent/NavigationContent.tsx View File

@@ -66,7 +66,7 @@ const NavigationContent: React.FC<Props> = ({ abilities }) => {
{ {
icon: <WorkHistory />, icon: <WorkHistory />,
label: "User Workspace", label: "User Workspace",
path: "/home",
path: "/home",
showOnMobile: true, showOnMobile: true,
}, },
{ {
@@ -131,7 +131,14 @@ const NavigationContent: React.FC<Props> = ({ abilities }) => {
// }, // },
{ icon: <Assignment />, label: "Project Management", path: "/projects", isHidden: ![MAINTAIN_PROJECT].some((ability) => abilities?.includes(ability)) }, { icon: <Assignment />, label: "Project Management", path: "/projects", isHidden: ![MAINTAIN_PROJECT].some((ability) => abilities?.includes(ability)) },
{ icon: <Task />, label: "Task Template", path: "/tasks", isHidden: ![MAINTAIN_TASK_TEMPLATE].some((ability) => abilities?.includes(ability)) }, { icon: <Task />, label: "Task Template", path: "/tasks", isHidden: ![MAINTAIN_TASK_TEMPLATE].some((ability) => abilities?.includes(ability)) },
{ icon: <Payments />, label: "Invoice", path: "/invoice" },
{
icon: <Payments />,
label: "Invoice",
path: "/invoice",
isHidden: ![VIEW_MASTERDATA, MAINTAIN_MASTERDATA].some((ability) =>
abilities!.includes(ability),
),
},
{ {
icon: <Analytics />, icon: <Analytics />,
label: "Analysis Report", label: "Analysis Report",


+ 6
- 2
src/components/SubsidiarySearch/SubsidiarySearch.tsx View File

@@ -1,6 +1,6 @@
"use client"; "use client";


import React, { useCallback, useMemo, useState } from "react";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import SearchBox, { Criterion } from "../SearchBox"; import SearchBox, { Criterion } from "../SearchBox";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import SearchResults, { Column } from "../SearchResults"; import SearchResults, { Column } from "../SearchResults";
@@ -24,6 +24,10 @@ const SubsidiarySearch: React.FC<Props> = ({ subsidiaries }) => {
const searchParams = useSearchParams() const searchParams = useSearchParams()


const [filteredSubsidiaries, setFilteredSubsidiaries] = useState(subsidiaries); const [filteredSubsidiaries, setFilteredSubsidiaries] = useState(subsidiaries);
useEffect(() => {
setFilteredSubsidiaries(subsidiaries)
}, [subsidiaries])

const searchCriteria: Criterion<SearchParamNames>[] = useMemo( const searchCriteria: Criterion<SearchParamNames>[] = useMemo(
() => [ () => [
{ label: t("Subsidiary Code"), paramName: "code", type: "text" }, { label: t("Subsidiary Code"), paramName: "code", type: "text" },
@@ -48,7 +52,7 @@ const SubsidiarySearch: React.FC<Props> = ({ subsidiaries }) => {


successDialog(t("Delete Success"), t) successDialog(t("Delete Success"), t)


setFilteredSubsidiaries((prev) => prev.filter((obj) => obj.id !== subsidiary.id))
// setFilteredSubsidiaries((prev) => prev.filter((obj) => obj.id !== subsidiary.id))
}, t) }, t)
}, []); }, []);




+ 3
- 0
src/middleware.ts View File

@@ -121,6 +121,9 @@ export default async function middleware(
if (req.nextUrl.pathname.startsWith('/settings/staff/edit')) { if (req.nextUrl.pathname.startsWith('/settings/staff/edit')) {
isAuth = [VIEW_STAFF_PROFILE].some((ability) => abilities.includes(ability)); isAuth = [VIEW_STAFF_PROFILE].some((ability) => abilities.includes(ability));
} }
if (req.nextUrl.pathname.startsWith('/invoice')) {
isAuth = [IMPORT_INVOICE].some((ability) => abilities.includes(ability));
}
return isAuth return isAuth
} }
} }


Loading…
Cancel
Save