diff --git a/.gitignore b/.gitignore
index 5ef6a520..82965e2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,3 +39,9 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
+
+# prettier
+.prettierrc
+
+# idea
+.idea
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 00000000..250df482
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,15 @@
+{
+ "singleQuote": true,
+ "jsxSingleQuote": true,
+ "endOfLine": "lf",
+ "arrowParens": "always",
+ "bracketSpacing": true,
+ "embeddedLanguageFormatting": "auto",
+ "htmlWhitespaceSensitivity": "css",
+ "printWidth": 80,
+ "proseWrap": "preserve",
+ "quoteProps": "as-needed",
+ "semi": true,
+ "tabWidth": 2,
+ "trailingComma": "es5"
+}
diff --git a/package-lock.json b/package-lock.json
index ba8fc9b0..1aa69d33 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,9 +17,11 @@
"next": "15.5.3",
"react": "19.1.0",
"react-dom": "19.1.0",
+ "react-hot-toast": "^2.6.0",
"react-select": "^5.10.2",
"swr": "^2.3.6",
"tailwind-merge": "^3.3.1",
+ "use-debounce": "^10.0.6",
"yup": "^1.7.0",
"zustand": "^5.0.8"
},
@@ -4039,6 +4041,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/goober": {
+ "version": "2.1.18",
+ "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.18.tgz",
+ "integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "csstype": "^3.0.10"
+ }
+ },
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@@ -5760,6 +5771,23 @@
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==",
"license": "MIT"
},
+ "node_modules/react-hot-toast": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz",
+ "integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==",
+ "license": "MIT",
+ "dependencies": {
+ "csstype": "^3.1.3",
+ "goober": "^2.1.16"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "react": ">=16",
+ "react-dom": ">=16"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -6792,6 +6820,18 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-debounce": {
+ "version": "10.0.6",
+ "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-10.0.6.tgz",
+ "integrity": "sha512-C5OtPyhAZgVoteO9heXMTdW7v/IbFI+8bSVKYCJrSmiWWCLsbUxiBSp4t9v0hNBTGY97bT72ydDIDyGSFWfwXg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/use-isomorphic-layout-effect": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz",
diff --git a/package.json b/package.json
index c88a9618..8adf6787 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
- "dev": "next dev --turbopack",
+ "dev": "eslint && next dev --turbopack",
"build": "next build --turbopack",
"start": "next start",
"lint": "eslint"
@@ -18,9 +18,11 @@
"next": "15.5.3",
"react": "19.1.0",
"react-dom": "19.1.0",
+ "react-hot-toast": "^2.6.0",
"react-select": "^5.10.2",
"swr": "^2.3.6",
"tailwind-merge": "^3.3.1",
+ "use-debounce": "^10.0.6",
"yup": "^1.7.0",
"zustand": "^5.0.8"
},
diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx
new file mode 100644
index 00000000..4f2c344e
--- /dev/null
+++ b/src/app/dashboard/page.tsx
@@ -0,0 +1,9 @@
+const Dashboard = () => {
+ return (
+
+ );
+};
+
+export default Dashboard;
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 793f0b93..ef28da38 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,6 +1,10 @@
import type { Metadata, Viewport } from 'next';
import { Inter } from 'next/font/google';
-import './globals.css';
+import '@/app/globals.css';
+
+import { Toaster } from 'react-hot-toast';
+import MainDrawer from '@/components/MainDrawer';
+import RequireAuth from '@/components/helper/RequireAuth';
const inter = Inter({
variable: '--font-inter',
@@ -26,7 +30,11 @@ export default function RootLayout({
return (
- {children}
+
+ {children}
+
+
+
);
diff --git a/src/app/master-data/area/add/page.tsx b/src/app/master-data/area/add/page.tsx
new file mode 100644
index 00000000..ed23b0b7
--- /dev/null
+++ b/src/app/master-data/area/add/page.tsx
@@ -0,0 +1,11 @@
+import AreaForm from '@/components/pages/master-data/area/form/AreaForm';
+
+const AddNonstock = () => {
+ return (
+
+ );
+};
+
+export default AddNonstock;
diff --git a/src/app/master-data/area/detail/edit/page.tsx b/src/app/master-data/area/detail/edit/page.tsx
new file mode 100644
index 00000000..4b29d792
--- /dev/null
+++ b/src/app/master-data/area/detail/edit/page.tsx
@@ -0,0 +1,47 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import AreaForm from '@/components/pages/master-data/area/form/AreaForm';
+
+import { AreaApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const AreaEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const areaId = searchParams.get('areaId');
+
+ const { data: area, isLoading: isLoadingArea } = useSWR(
+ areaId,
+ (id: number) => AreaApi.getSingle(id)
+ );
+
+ if (!areaId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingArea && (!area || isResponseError(area))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingArea &&
}
+ {!isLoadingArea && isResponseSuccess(area) && (
+
+ )}
+
+ );
+};
+
+export default AreaEdit;
diff --git a/src/app/master-data/area/detail/layout.tsx b/src/app/master-data/area/detail/layout.tsx
new file mode 100644
index 00000000..7220dfa1
--- /dev/null
+++ b/src/app/master-data/area/detail/layout.tsx
@@ -0,0 +1,11 @@
+import SuspenseHelper from '@/components/helper/SuspenseHelper';
+
+const Layout = ({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/master-data/area/detail/page.tsx b/src/app/master-data/area/detail/page.tsx
new file mode 100644
index 00000000..c786ac0d
--- /dev/null
+++ b/src/app/master-data/area/detail/page.tsx
@@ -0,0 +1,47 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import AreaForm from '@/components/pages/master-data/area/form/AreaForm';
+
+import { AreaApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const AreaDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const areaId = searchParams.get('areaId');
+
+ const { data: area, isLoading: isLoadingArea } = useSWR(
+ areaId,
+ (id: number) => AreaApi.getSingle(id)
+ );
+
+ if (!areaId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingArea && (!area || isResponseError(area))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingArea &&
}
+ {!isLoadingArea && isResponseSuccess(area) && (
+
+ )}
+
+ );
+};
+
+export default AreaDetail;
diff --git a/src/app/master-data/area/page.tsx b/src/app/master-data/area/page.tsx
new file mode 100644
index 00000000..f8789af2
--- /dev/null
+++ b/src/app/master-data/area/page.tsx
@@ -0,0 +1,11 @@
+import AreasTable from '@/components/pages/master-data/area/AreasTable';
+
+const Nonstock = () => {
+ return (
+
+ );
+};
+
+export default Nonstock;
diff --git a/src/app/master-data/bank/add/page.tsx b/src/app/master-data/bank/add/page.tsx
new file mode 100644
index 00000000..0bb6e532
--- /dev/null
+++ b/src/app/master-data/bank/add/page.tsx
@@ -0,0 +1,11 @@
+import BankForm from '@/components/pages/master-data/bank/form/BankForm';
+
+const AddBank = () => {
+ return (
+
+
+
+ );
+};
+
+export default AddBank;
diff --git a/src/app/master-data/bank/detail/edit/page.tsx b/src/app/master-data/bank/detail/edit/page.tsx
new file mode 100644
index 00000000..a0939af9
--- /dev/null
+++ b/src/app/master-data/bank/detail/edit/page.tsx
@@ -0,0 +1,47 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import BankForm from '@/components/pages/master-data/bank/form/BankForm';
+
+import { BankApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const BankEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const bankId = searchParams.get('bankId');
+
+ const { data: bank, isLoading: isLoadingBank } = useSWR(
+ bankId,
+ (id: number) => BankApi.getSingle(id)
+ );
+
+ if (!bankId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingBank && (!bank || isResponseError(bank))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingBank && }
+ {!isLoadingBank && isResponseSuccess(bank) && (
+
+ )}
+
+ );
+};
+
+export default BankEdit;
diff --git a/src/app/master-data/bank/detail/layout.tsx b/src/app/master-data/bank/detail/layout.tsx
new file mode 100644
index 00000000..7220dfa1
--- /dev/null
+++ b/src/app/master-data/bank/detail/layout.tsx
@@ -0,0 +1,11 @@
+import SuspenseHelper from '@/components/helper/SuspenseHelper';
+
+const Layout = ({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/master-data/bank/detail/page.tsx b/src/app/master-data/bank/detail/page.tsx
new file mode 100644
index 00000000..bd1661d8
--- /dev/null
+++ b/src/app/master-data/bank/detail/page.tsx
@@ -0,0 +1,47 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import BankForm from '@/components/pages/master-data/bank/form/BankForm';
+
+import { BankApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const BankDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const bankId = searchParams.get('bankId');
+
+ const { data: bank, isLoading: isLoadingBank } = useSWR(
+ bankId,
+ (id: number) => BankApi.getSingle(id)
+ );
+
+ if (!bankId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingBank && (!bank || isResponseError(bank))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingBank && }
+ {!isLoadingBank && isResponseSuccess(bank) && (
+
+ )}
+
+ );
+};
+
+export default BankDetail;
diff --git a/src/app/master-data/bank/page.tsx b/src/app/master-data/bank/page.tsx
new file mode 100644
index 00000000..3f913c55
--- /dev/null
+++ b/src/app/master-data/bank/page.tsx
@@ -0,0 +1,11 @@
+import BanksTable from '@/components/pages/master-data/bank/BanksTable';
+
+const Bank = () => {
+ return (
+
+ );
+};
+
+export default Bank;
diff --git a/src/app/master-data/customer/add/page.tsx b/src/app/master-data/customer/add/page.tsx
new file mode 100644
index 00000000..a1096f02
--- /dev/null
+++ b/src/app/master-data/customer/add/page.tsx
@@ -0,0 +1,11 @@
+import CustomerForm from "@/components/pages/master-data/customer/form/CustomerForm";
+
+const AddCustomer = () => {
+ return (
+
+ );
+}
+
+export default AddCustomer;
\ No newline at end of file
diff --git a/src/app/master-data/customer/detail/edit/page.tsx b/src/app/master-data/customer/detail/edit/page.tsx
new file mode 100644
index 00000000..3fe8de52
--- /dev/null
+++ b/src/app/master-data/customer/detail/edit/page.tsx
@@ -0,0 +1,47 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+import { CustomerApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+import CustomerForm from '@/components/pages/master-data/customer/form/CustomerForm';
+
+const CustomerEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const costumerId = searchParams.get('customerId');
+
+ const { data: costumer, isLoading: isLoadingCostumer } = useSWR(
+ costumerId,
+ (id: number) => CustomerApi.getSingle(id)
+ );
+
+ if (!costumerId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingCostumer && (!costumer || isResponseError(costumer))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingCostumer && (
+
+ )}
+ {!isLoadingCostumer && isResponseSuccess(costumer) && (
+
+ )}
+
+ );
+};
+
+export default CustomerEdit;
diff --git a/src/app/master-data/customer/detail/page.tsx b/src/app/master-data/customer/detail/page.tsx
new file mode 100644
index 00000000..263458c2
--- /dev/null
+++ b/src/app/master-data/customer/detail/page.tsx
@@ -0,0 +1,45 @@
+'use client'
+
+import { useRouter, useSearchParams } from "next/navigation";
+import useSWR from "swr";
+import { CustomerApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from "@/lib/api-helper";
+import CustomerForm from "@/components/pages/master-data/customer/form/CustomerForm";
+
+const CustomerDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const costumerId = searchParams.get("customerId");
+
+ const { data: costumer, isLoading: isLoadingCostumer } = useSWR(
+ costumerId,
+ (id: number) => CustomerApi.getSingle(id)
+ );
+
+ if(!costumerId){
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if(!isLoadingCostumer && (!costumer || isResponseError(costumer))){
+ router.replace("/404");
+ return;
+ }
+
+ return (
+
+ {isLoadingCostumer && }
+ {!isLoadingCostumer && isResponseSuccess(costumer) && (
+
+ )}
+
+ )
+};
+
+export default CustomerDetail;
diff --git a/src/app/master-data/customer/page.tsx b/src/app/master-data/customer/page.tsx
new file mode 100644
index 00000000..b80401f1
--- /dev/null
+++ b/src/app/master-data/customer/page.tsx
@@ -0,0 +1,11 @@
+import CustomersTable from "@/components/pages/master-data/customer/CustomersTable";
+
+const Customer = () => {
+ return (
+
+ )
+};
+
+export default Customer;
\ No newline at end of file
diff --git a/src/app/master-data/fcr/add/page.tsx b/src/app/master-data/fcr/add/page.tsx
new file mode 100644
index 00000000..9a74034d
--- /dev/null
+++ b/src/app/master-data/fcr/add/page.tsx
@@ -0,0 +1,11 @@
+import FcrForm from '@/components/pages/master-data/fcr/form/FcrForm';
+
+const AddFcr = () => {
+ return (
+
+
+
+ );
+};
+
+export default AddFcr;
diff --git a/src/app/master-data/fcr/detail/edit/page.tsx b/src/app/master-data/fcr/detail/edit/page.tsx
new file mode 100644
index 00000000..54277e8a
--- /dev/null
+++ b/src/app/master-data/fcr/detail/edit/page.tsx
@@ -0,0 +1,52 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import FcrForm from '@/components/pages/master-data/fcr/form/FcrForm';
+
+import { FcrApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+import { BaseApiResponse } from '@/types/api/api-general';
+import { FcrWithStandards } from '@/types/api/master-data/fcr';
+
+const FcrEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const fcrId = searchParams.get('fcrId');
+
+ const { data: fcr, isLoading: isLoadingFcr } = useSWR(
+ fcrId,
+ (id: number) =>
+ FcrApi.getSingle(id) as Promise<
+ BaseApiResponse | undefined
+ >
+ );
+
+ if (!fcrId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingFcr && (!fcr || isResponseError(fcr))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingFcr && }
+ {!isLoadingFcr && isResponseSuccess(fcr) && (
+
+ )}
+
+ );
+};
+
+export default FcrEdit;
diff --git a/src/app/master-data/fcr/detail/layout.tsx b/src/app/master-data/fcr/detail/layout.tsx
new file mode 100644
index 00000000..7220dfa1
--- /dev/null
+++ b/src/app/master-data/fcr/detail/layout.tsx
@@ -0,0 +1,11 @@
+import SuspenseHelper from '@/components/helper/SuspenseHelper';
+
+const Layout = ({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/master-data/fcr/detail/page.tsx b/src/app/master-data/fcr/detail/page.tsx
new file mode 100644
index 00000000..5db1ab32
--- /dev/null
+++ b/src/app/master-data/fcr/detail/page.tsx
@@ -0,0 +1,52 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import FcrForm from '@/components/pages/master-data/fcr/form/FcrForm';
+
+import { FcrApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+import { FcrWithStandards } from '@/types/api/master-data/fcr';
+import { BaseApiResponse } from '@/types/api/api-general';
+
+const FcrDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const fcrId = searchParams.get('fcrId');
+
+ const { data: fcr, isLoading: isLoadingFcr } = useSWR(
+ fcrId,
+ (id: number) =>
+ FcrApi.getSingle(id) as Promise<
+ BaseApiResponse | undefined
+ >
+ );
+
+ if (!fcrId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingFcr && (!fcr || isResponseError(fcr))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingFcr && }
+ {!isLoadingFcr && isResponseSuccess(fcr) && (
+
+ )}
+
+ );
+};
+
+export default FcrDetail;
diff --git a/src/app/master-data/fcr/page.tsx b/src/app/master-data/fcr/page.tsx
new file mode 100644
index 00000000..9ca9c55d
--- /dev/null
+++ b/src/app/master-data/fcr/page.tsx
@@ -0,0 +1,11 @@
+import FcrsTable from '@/components/pages/master-data/fcr/FcrsTable';
+
+const Fcr = () => {
+ return (
+
+ );
+};
+
+export default Fcr;
diff --git a/src/app/master-data/kandang/add/page.tsx b/src/app/master-data/kandang/add/page.tsx
new file mode 100644
index 00000000..238799cd
--- /dev/null
+++ b/src/app/master-data/kandang/add/page.tsx
@@ -0,0 +1,11 @@
+import KandangForm from '@/components/pages/master-data/kandang/form/KandangForm';
+
+const AddNonstock = () => {
+ return (
+
+
+
+ );
+};
+
+export default AddNonstock;
diff --git a/src/app/master-data/kandang/detail/edit/page.tsx b/src/app/master-data/kandang/detail/edit/page.tsx
new file mode 100644
index 00000000..561d6f1f
--- /dev/null
+++ b/src/app/master-data/kandang/detail/edit/page.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import KandangForm from '@/components/pages/master-data/kandang/form/KandangForm';
+
+import { KandangApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const KandangEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const kandangId = searchParams.get('kandangId');
+
+ const { data: kandang, isLoading: isLoadingKandang } = useSWR(
+ kandangId,
+ (id: number) => KandangApi.getSingle(id)
+ );
+
+ if (!kandangId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingKandang && (!kandang || isResponseError(kandang))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingKandang && (
+
+ )}
+ {!isLoadingKandang && isResponseSuccess(kandang) && (
+
+ )}
+
+ );
+};
+
+export default KandangEdit;
diff --git a/src/app/master-data/kandang/detail/layout.tsx b/src/app/master-data/kandang/detail/layout.tsx
new file mode 100644
index 00000000..7220dfa1
--- /dev/null
+++ b/src/app/master-data/kandang/detail/layout.tsx
@@ -0,0 +1,11 @@
+import SuspenseHelper from '@/components/helper/SuspenseHelper';
+
+const Layout = ({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/master-data/kandang/detail/page.tsx b/src/app/master-data/kandang/detail/page.tsx
new file mode 100644
index 00000000..a5b4f0e9
--- /dev/null
+++ b/src/app/master-data/kandang/detail/page.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import KandangForm from '@/components/pages/master-data/kandang/form/KandangForm';
+
+import { KandangApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const KandangDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const kandangId = searchParams.get('kandangId');
+
+ const { data: kandang, isLoading: isLoadingKandang } = useSWR(
+ kandangId,
+ (id: number) => KandangApi.getSingle(id)
+ );
+
+ if (!kandangId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingKandang && (!kandang || isResponseError(kandang))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingKandang && (
+
+ )}
+ {!isLoadingKandang && isResponseSuccess(kandang) && (
+
+ )}
+
+ );
+};
+
+export default KandangDetail;
diff --git a/src/app/master-data/kandang/page.tsx b/src/app/master-data/kandang/page.tsx
new file mode 100644
index 00000000..293eb0da
--- /dev/null
+++ b/src/app/master-data/kandang/page.tsx
@@ -0,0 +1,11 @@
+import KandangsTable from '@/components/pages/master-data/kandang/KandangsTable';
+
+const Nonstock = () => {
+ return (
+
+ );
+};
+
+export default Nonstock;
diff --git a/src/app/master-data/location/add/page.tsx b/src/app/master-data/location/add/page.tsx
new file mode 100644
index 00000000..56f668fd
--- /dev/null
+++ b/src/app/master-data/location/add/page.tsx
@@ -0,0 +1,11 @@
+import LocationForm from '@/components/pages/master-data/location/form/LocationForm';
+
+const AddNonstock = () => {
+ return (
+
+
+
+ );
+};
+
+export default AddNonstock;
diff --git a/src/app/master-data/location/detail/edit/page.tsx b/src/app/master-data/location/detail/edit/page.tsx
new file mode 100644
index 00000000..a97f5672
--- /dev/null
+++ b/src/app/master-data/location/detail/edit/page.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import LocationForm from '@/components/pages/master-data/location/form/LocationForm';
+
+import { LocationApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const LocationEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const locationId = searchParams.get('locationId');
+
+ const { data: location, isLoading: isLoadingLocation } = useSWR(
+ locationId,
+ (id: number) => LocationApi.getSingle(id)
+ );
+
+ if (!locationId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingLocation && (!location || isResponseError(location))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingLocation && (
+
+ )}
+ {!isLoadingLocation && isResponseSuccess(location) && (
+
+ )}
+
+ );
+};
+
+export default LocationEdit;
diff --git a/src/app/master-data/location/detail/layout.tsx b/src/app/master-data/location/detail/layout.tsx
new file mode 100644
index 00000000..7220dfa1
--- /dev/null
+++ b/src/app/master-data/location/detail/layout.tsx
@@ -0,0 +1,11 @@
+import SuspenseHelper from '@/components/helper/SuspenseHelper';
+
+const Layout = ({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/master-data/location/detail/page.tsx b/src/app/master-data/location/detail/page.tsx
new file mode 100644
index 00000000..bb0fbe4c
--- /dev/null
+++ b/src/app/master-data/location/detail/page.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import LocationForm from '@/components/pages/master-data/location/form/LocationForm';
+
+import { LocationApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const LocationDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const locationId = searchParams.get('locationId');
+
+ const { data: location, isLoading: isLoadingLocation } = useSWR(
+ locationId,
+ (id: number) => LocationApi.getSingle(id)
+ );
+
+ if (!locationId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingLocation && (!location || isResponseError(location))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingLocation && (
+
+ )}
+ {!isLoadingLocation && isResponseSuccess(location) && (
+
+ )}
+
+ );
+};
+
+export default LocationDetail;
diff --git a/src/app/master-data/location/page.tsx b/src/app/master-data/location/page.tsx
new file mode 100644
index 00000000..338fdbff
--- /dev/null
+++ b/src/app/master-data/location/page.tsx
@@ -0,0 +1,11 @@
+import LocationsTable from '@/components/pages/master-data/location/LocationsTable';
+
+const Nonstock = () => {
+ return (
+
+ );
+};
+
+export default Nonstock;
diff --git a/src/app/master-data/nonstock/add/page.tsx b/src/app/master-data/nonstock/add/page.tsx
new file mode 100644
index 00000000..2bde94ed
--- /dev/null
+++ b/src/app/master-data/nonstock/add/page.tsx
@@ -0,0 +1,11 @@
+import NonstockForm from '@/components/pages/master-data/nonstock/form/NonstockForm';
+
+const AddNonstock = () => {
+ return (
+
+
+
+ );
+};
+
+export default AddNonstock;
diff --git a/src/app/master-data/nonstock/detail/edit/page.tsx b/src/app/master-data/nonstock/detail/edit/page.tsx
new file mode 100644
index 00000000..3b3db5f5
--- /dev/null
+++ b/src/app/master-data/nonstock/detail/edit/page.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import NonstockForm from '@/components/pages/master-data/nonstock/form/NonstockForm';
+
+import { NonstockApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const NonstockEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const nonstockId = searchParams.get('nonstockId');
+
+ const { data: nonstock, isLoading: isLoadingNonstock } = useSWR(
+ nonstockId,
+ (id: number) => NonstockApi.getSingle(id)
+ );
+
+ if (!nonstockId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingNonstock && (!nonstock || isResponseError(nonstock))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingNonstock && (
+
+ )}
+ {!isLoadingNonstock && isResponseSuccess(nonstock) && (
+
+ )}
+
+ );
+};
+
+export default NonstockEdit;
diff --git a/src/app/master-data/nonstock/detail/layout.tsx b/src/app/master-data/nonstock/detail/layout.tsx
new file mode 100644
index 00000000..7220dfa1
--- /dev/null
+++ b/src/app/master-data/nonstock/detail/layout.tsx
@@ -0,0 +1,11 @@
+import SuspenseHelper from '@/components/helper/SuspenseHelper';
+
+const Layout = ({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/master-data/nonstock/detail/page.tsx b/src/app/master-data/nonstock/detail/page.tsx
new file mode 100644
index 00000000..798a843e
--- /dev/null
+++ b/src/app/master-data/nonstock/detail/page.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import NonstockForm from '@/components/pages/master-data/nonstock/form/NonstockForm';
+
+import { NonstockApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const NonstockDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const nonstockId = searchParams.get('nonstockId');
+
+ const { data: nonstock, isLoading: isLoadingNonstock } = useSWR(
+ nonstockId,
+ (id: number) => NonstockApi.getSingle(id)
+ );
+
+ if (!nonstockId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingNonstock && (!nonstock || isResponseError(nonstock))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingNonstock && (
+
+ )}
+ {!isLoadingNonstock && isResponseSuccess(nonstock) && (
+
+ )}
+
+ );
+};
+
+export default NonstockDetail;
diff --git a/src/app/master-data/nonstock/page.tsx b/src/app/master-data/nonstock/page.tsx
new file mode 100644
index 00000000..0812a5e2
--- /dev/null
+++ b/src/app/master-data/nonstock/page.tsx
@@ -0,0 +1,11 @@
+import NonstocksTable from '@/components/pages/master-data/nonstock/NonstocksTable';
+
+const Nonstock = () => {
+ return (
+
+ );
+};
+
+export default Nonstock;
diff --git a/src/app/master-data/product-category/add/page.tsx b/src/app/master-data/product-category/add/page.tsx
new file mode 100644
index 00000000..0993ba7a
--- /dev/null
+++ b/src/app/master-data/product-category/add/page.tsx
@@ -0,0 +1,11 @@
+import ProductCategoryForm from "@/components/pages/master-data/product-category/form/ProductCategoryForm";
+
+const AddProductCategory = () => {
+ return (
+
+ );
+};
+
+export default AddProductCategory;
\ No newline at end of file
diff --git a/src/app/master-data/product-category/detail/edit/page.tsx b/src/app/master-data/product-category/detail/edit/page.tsx
new file mode 100644
index 00000000..6bc10644
--- /dev/null
+++ b/src/app/master-data/product-category/detail/edit/page.tsx
@@ -0,0 +1,47 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import ProductCategoryForm from '@/components/pages/master-data/product-category/form/ProductCategoryForm';
+
+import { ProductCategoryApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const ProductCategoryEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const productCategoryId = searchParams.get('productCategoryId');
+
+ const { data: productCategory, isLoading: isLoadingProductCategory } = useSWR(
+ productCategoryId,
+ (id: number) => ProductCategoryApi.getSingle(id)
+ );
+
+ if (!productCategoryId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingProductCategory && (!productCategory || isResponseError(productCategory))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingProductCategory &&
}
+ {!isLoadingProductCategory && isResponseSuccess(productCategory) && (
+
+ )}
+
+ );
+}
+
+export default ProductCategoryEdit;
\ No newline at end of file
diff --git a/src/app/master-data/product-category/detail/layout.tsx b/src/app/master-data/product-category/detail/layout.tsx
new file mode 100644
index 00000000..7220dfa1
--- /dev/null
+++ b/src/app/master-data/product-category/detail/layout.tsx
@@ -0,0 +1,11 @@
+import SuspenseHelper from '@/components/helper/SuspenseHelper';
+
+const Layout = ({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/master-data/product-category/detail/page.tsx b/src/app/master-data/product-category/detail/page.tsx
new file mode 100644
index 00000000..cba06fdb
--- /dev/null
+++ b/src/app/master-data/product-category/detail/page.tsx
@@ -0,0 +1,47 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import ProductCategoryForm from '@/components/pages/master-data/product-category/form/ProductCategoryForm';
+
+import { ProductCategoryApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const ProductCategoryDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const productCategoryId = searchParams.get('productCategoryId');
+
+ const { data: productCategory, isLoading: isLoadingProductCategory } = useSWR(
+ productCategoryId,
+ (id: number) => ProductCategoryApi.getSingle(id)
+ );
+
+ if (!productCategoryId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingProductCategory && (!productCategory || isResponseError(productCategory))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingProductCategory &&
}
+ {!isLoadingProductCategory && isResponseSuccess(productCategory) && (
+
+ )}
+
+ );
+};
+
+export default ProductCategoryDetail;
diff --git a/src/app/master-data/product-category/page.tsx b/src/app/master-data/product-category/page.tsx
new file mode 100644
index 00000000..5ec6d555
--- /dev/null
+++ b/src/app/master-data/product-category/page.tsx
@@ -0,0 +1,11 @@
+import ProductCategoryTable from "@/components/pages/master-data/product-category/ProductCategoryTable";
+
+const ProductCategory = () => {
+ return (
+
+ );
+};
+
+export default ProductCategory;
\ No newline at end of file
diff --git a/src/app/master-data/product/add/page.tsx b/src/app/master-data/product/add/page.tsx
new file mode 100644
index 00000000..7cc995b6
--- /dev/null
+++ b/src/app/master-data/product/add/page.tsx
@@ -0,0 +1,11 @@
+import ProductForm from '@/components/pages/master-data/product/form/ProductForm';
+
+const AddProduct = () => {
+ return (
+
+ );
+};
+
+export default AddProduct;
\ No newline at end of file
diff --git a/src/app/master-data/product/detail/edit/page.tsx b/src/app/master-data/product/detail/edit/page.tsx
new file mode 100644
index 00000000..96cfdc42
--- /dev/null
+++ b/src/app/master-data/product/detail/edit/page.tsx
@@ -0,0 +1,45 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import ProductForm from '@/components/pages/master-data/product/form/ProductForm';
+import { ProductApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const ProductEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const productId = searchParams.get('productId');
+
+ const { data: product, isLoading } = useSWR(
+ productId,
+ (id: number) => ProductApi.getSingle(id)
+ );
+
+ if (!productId) {
+ router.back();
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoading && (!product || isResponseError(product))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoading &&
}
+ {!isLoading && isResponseSuccess(product) && (
+
+ )}
+
+ );
+};
+
+export default ProductEdit;
\ No newline at end of file
diff --git a/src/app/master-data/product/detail/layout.tsx b/src/app/master-data/product/detail/layout.tsx
new file mode 100644
index 00000000..7220dfa1
--- /dev/null
+++ b/src/app/master-data/product/detail/layout.tsx
@@ -0,0 +1,11 @@
+import SuspenseHelper from '@/components/helper/SuspenseHelper';
+
+const Layout = ({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/master-data/product/detail/page.tsx b/src/app/master-data/product/detail/page.tsx
new file mode 100644
index 00000000..916a44d0
--- /dev/null
+++ b/src/app/master-data/product/detail/page.tsx
@@ -0,0 +1,45 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import ProductForm from '@/components/pages/master-data/product/form/ProductForm';
+import { ProductApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const ProductDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const productId = searchParams.get('productId');
+
+ const { data: product, isLoading } = useSWR(
+ productId,
+ (id: number) => ProductApi.getSingle(id)
+ );
+
+ if (!productId) {
+ router.back();
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoading && (!product || isResponseError(product))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoading &&
}
+ {!isLoading && isResponseSuccess(product) && (
+
+ )}
+
+ );
+};
+
+export default ProductDetail;
\ No newline at end of file
diff --git a/src/app/master-data/product/page.tsx b/src/app/master-data/product/page.tsx
new file mode 100644
index 00000000..6014aeb9
--- /dev/null
+++ b/src/app/master-data/product/page.tsx
@@ -0,0 +1,11 @@
+import ProductsTable from "@/components/pages/master-data/product/ProductTable";
+
+const Product = () => {
+ return (
+
+ );
+};
+
+export default Product;
\ No newline at end of file
diff --git a/src/app/master-data/supplier/add/page.tsx b/src/app/master-data/supplier/add/page.tsx
new file mode 100644
index 00000000..8a95c3c6
--- /dev/null
+++ b/src/app/master-data/supplier/add/page.tsx
@@ -0,0 +1,11 @@
+import SupplierForm from '@/components/pages/master-data/supplier/form/SupplierForm';
+
+const AddSupplier = () => {
+ return (
+
+ );
+};
+
+export default AddSupplier;
\ No newline at end of file
diff --git a/src/app/master-data/supplier/detail/edit/page.tsx b/src/app/master-data/supplier/detail/edit/page.tsx
new file mode 100644
index 00000000..103db73d
--- /dev/null
+++ b/src/app/master-data/supplier/detail/edit/page.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import SupplierForm from '@/components/pages/master-data/supplier/form/SupplierForm';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+import { SupplierApi } from '@/services/api/master-data';
+import { useSearchParams, useRouter } from 'next/navigation';
+import useSWR from 'swr';
+
+const SupplierEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ // Get Query Params
+ const supplierId = searchParams.get('supplierId');
+
+ // Fetch Data
+ const { data: supplier, isLoading: isLoadingSupplier } = useSWR(
+ supplierId,
+ (id: number) => SupplierApi.getSingle(id)
+ );
+
+ if (!supplierId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingSupplier && (!supplier || isResponseError(supplier))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingSupplier && (
+
+ )}
+ {!isLoadingSupplier && isResponseSuccess(supplier) && (
+
+ )}
+
+ );
+};
+
+export default SupplierEdit;
diff --git a/src/app/master-data/supplier/detail/page.tsx b/src/app/master-data/supplier/detail/page.tsx
new file mode 100644
index 00000000..433fa043
--- /dev/null
+++ b/src/app/master-data/supplier/detail/page.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import SupplierForm from '@/components/pages/master-data/supplier/form/SupplierForm';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+import { SupplierApi } from '@/services/api/master-data';
+import { useSearchParams, useRouter } from 'next/navigation';
+import useSWR from 'swr';
+
+const SupplierDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ // Get Query Params
+ const supplierId = searchParams.get('supplierId');
+
+ // Fetch Data
+ const { data: supplier, isLoading: isLoadingSupplier } = useSWR(
+ supplierId,
+ (id: number) => SupplierApi.getSingle(id)
+ );
+
+ if (!supplierId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingSupplier && (!supplier || isResponseError(supplier))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingSupplier && (
+
+ )}
+ {!isLoadingSupplier && isResponseSuccess(supplier) && (
+
+ )}
+
+ );
+};
+
+export default SupplierDetail;
\ No newline at end of file
diff --git a/src/app/master-data/supplier/page.tsx b/src/app/master-data/supplier/page.tsx
new file mode 100644
index 00000000..1f54bd0d
--- /dev/null
+++ b/src/app/master-data/supplier/page.tsx
@@ -0,0 +1,11 @@
+import SuppliersTable from "@/components/pages/master-data/supplier/SupplierTable";
+
+const Supplier = () => {
+ return (
+
+ );
+};
+
+export default Supplier;
diff --git a/src/app/master-data/uom/add/page.tsx b/src/app/master-data/uom/add/page.tsx
new file mode 100644
index 00000000..452aadf8
--- /dev/null
+++ b/src/app/master-data/uom/add/page.tsx
@@ -0,0 +1,11 @@
+import UomForm from '@/components/pages/master-data/uom/form/UomForm';
+
+const AddNonstock = () => {
+ return (
+
+
+
+ );
+};
+
+export default AddNonstock;
diff --git a/src/app/master-data/uom/detail/edit/page.tsx b/src/app/master-data/uom/detail/edit/page.tsx
new file mode 100644
index 00000000..48d7c823
--- /dev/null
+++ b/src/app/master-data/uom/detail/edit/page.tsx
@@ -0,0 +1,46 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import UomForm from '@/components/pages/master-data/uom/form/UomForm';
+
+import { UomApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const UomEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const uomId = searchParams.get('uomId');
+
+ const { data: uom, isLoading: isLoadingUom } = useSWR(uomId, (id: number) =>
+ UomApi.getSingle(id)
+ );
+
+ if (!uomId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingUom && (!uom || isResponseError(uom))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingUom && }
+ {!isLoadingUom && isResponseSuccess(uom) && (
+
+ )}
+
+ );
+};
+
+export default UomEdit;
diff --git a/src/app/master-data/uom/detail/layout.tsx b/src/app/master-data/uom/detail/layout.tsx
new file mode 100644
index 00000000..7220dfa1
--- /dev/null
+++ b/src/app/master-data/uom/detail/layout.tsx
@@ -0,0 +1,11 @@
+import SuspenseHelper from '@/components/helper/SuspenseHelper';
+
+const Layout = ({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/master-data/uom/detail/page.tsx b/src/app/master-data/uom/detail/page.tsx
new file mode 100644
index 00000000..b02af02b
--- /dev/null
+++ b/src/app/master-data/uom/detail/page.tsx
@@ -0,0 +1,46 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import UomForm from '@/components/pages/master-data/uom/form/UomForm';
+
+import { UomApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const UomDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const uomId = searchParams.get('uomId');
+
+ const { data: uom, isLoading: isLoadingUom } = useSWR(uomId, (id: number) =>
+ UomApi.getSingle(id)
+ );
+
+ if (!uomId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingUom && (!uom || isResponseError(uom))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingUom && }
+ {!isLoadingUom && isResponseSuccess(uom) && (
+
+ )}
+
+ );
+};
+
+export default UomDetail;
diff --git a/src/app/master-data/uom/page.tsx b/src/app/master-data/uom/page.tsx
new file mode 100644
index 00000000..689b9d0d
--- /dev/null
+++ b/src/app/master-data/uom/page.tsx
@@ -0,0 +1,11 @@
+import UomsTable from '@/components/pages/master-data/uom/UomsTable';
+
+const Nonstock = () => {
+ return (
+
+ );
+};
+
+export default Nonstock;
diff --git a/src/app/master-data/warehouse/add/page.tsx b/src/app/master-data/warehouse/add/page.tsx
new file mode 100644
index 00000000..7a8105a1
--- /dev/null
+++ b/src/app/master-data/warehouse/add/page.tsx
@@ -0,0 +1,11 @@
+import WarehouseForm from '@/components/pages/master-data/warehouse/form/WarehouseForm';
+
+const AddNonstock = () => {
+ return (
+
+
+
+ );
+};
+
+export default AddNonstock;
diff --git a/src/app/master-data/warehouse/detail/edit/page.tsx b/src/app/master-data/warehouse/detail/edit/page.tsx
new file mode 100644
index 00000000..a6498834
--- /dev/null
+++ b/src/app/master-data/warehouse/detail/edit/page.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import WarehouseForm from '@/components/pages/master-data/warehouse/form/WarehouseForm';
+
+import { WarehouseApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const WarehouseEdit = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const warehouseId = searchParams.get('warehouseId');
+
+ const { data: warehouse, isLoading: isLoadingWarehouse } = useSWR(
+ warehouseId,
+ (id: number) => WarehouseApi.getSingle(id)
+ );
+
+ if (!warehouseId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingWarehouse && (!warehouse || isResponseError(warehouse))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingWarehouse && (
+
+ )}
+ {!isLoadingWarehouse && isResponseSuccess(warehouse) && (
+
+ )}
+
+ );
+};
+
+export default WarehouseEdit;
diff --git a/src/app/master-data/warehouse/detail/layout.tsx b/src/app/master-data/warehouse/detail/layout.tsx
new file mode 100644
index 00000000..7220dfa1
--- /dev/null
+++ b/src/app/master-data/warehouse/detail/layout.tsx
@@ -0,0 +1,11 @@
+import SuspenseHelper from '@/components/helper/SuspenseHelper';
+
+const Layout = ({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) => {
+ return {children};
+};
+
+export default Layout;
diff --git a/src/app/master-data/warehouse/detail/page.tsx b/src/app/master-data/warehouse/detail/page.tsx
new file mode 100644
index 00000000..5a7c7042
--- /dev/null
+++ b/src/app/master-data/warehouse/detail/page.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import { useRouter, useSearchParams } from 'next/navigation';
+import useSWR from 'swr';
+
+import WarehouseForm from '@/components/pages/master-data/warehouse/form/WarehouseForm';
+
+import { WarehouseApi } from '@/services/api/master-data';
+import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
+
+const WarehouseDetail = () => {
+ const router = useRouter();
+ const searchParams = useSearchParams();
+
+ const warehouseId = searchParams.get('warehouseId');
+
+ const { data: warehouse, isLoading: isLoadingWarehouse } = useSWR(
+ warehouseId,
+ (id: number) => WarehouseApi.getSingle(id)
+ );
+
+ if (!warehouseId) {
+ router.back();
+
+ return (
+
+
+
+ );
+ }
+
+ if (!isLoadingWarehouse && (!warehouse || isResponseError(warehouse))) {
+ router.replace('/404');
+ return;
+ }
+
+ return (
+
+ {isLoadingWarehouse && (
+
+ )}
+ {!isLoadingWarehouse && isResponseSuccess(warehouse) && (
+
+ )}
+
+ );
+};
+
+export default WarehouseDetail;
diff --git a/src/app/master-data/warehouse/page.tsx b/src/app/master-data/warehouse/page.tsx
new file mode 100644
index 00000000..eb5ae416
--- /dev/null
+++ b/src/app/master-data/warehouse/page.tsx
@@ -0,0 +1,11 @@
+import WarehousesTable from '@/components/pages/master-data/warehouse/WarehousesTable';
+
+const Warehouse = () => {
+ return (
+
+ );
+};
+
+export default Warehouse;
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 8ac3364a..db9638df 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,4 +1,8 @@
+import { redirect } from 'next/navigation';
+
export default function Home() {
+ redirect('/dashboard');
+
return (
LTI ERP
diff --git a/src/components/Alert.tsx b/src/components/Alert.tsx
new file mode 100644
index 00000000..61792d0c
--- /dev/null
+++ b/src/components/Alert.tsx
@@ -0,0 +1,27 @@
+import { ReactNode } from 'react';
+
+import { cn } from '@/lib/helper';
+
+interface AlertProps {
+ variant?: 'outline' | 'dash' | 'soft';
+ color?: 'info' | 'success' | 'warning' | 'error';
+ children?: ReactNode;
+ className?: string;
+}
+
+const Alert = ({ children, variant, color, className }: AlertProps) => {
+ const alertBaseClassName = cn('alert', {
+ 'alert-soft': variant === 'soft',
+ 'alert-outline': variant === 'outline',
+ 'alert-dash': variant === 'dash',
+
+ 'alert-info': color === 'info',
+ 'alert-success': color === 'success',
+ 'alert-warning': color === 'warning',
+ 'alert-error': color === 'error',
+ });
+
+ return {children}
;
+};
+
+export default Alert;
diff --git a/src/components/Button.tsx b/src/components/Button.tsx
index 79ecb6d9..c67a29c2 100644
--- a/src/components/Button.tsx
+++ b/src/components/Button.tsx
@@ -1,4 +1,4 @@
-import react, { JSX } from 'react';
+import react from 'react';
import Link from 'next/link';
@@ -17,11 +17,12 @@ const Button = ({
type,
href,
variant,
- color,
+ color = 'primary',
isLoading,
className,
disabled,
onClick,
+ ...props
}: ButtonProps) => {
const btnBaseClassName = cn(
'btn',
@@ -49,6 +50,7 @@ const Button = ({
<>
{!href && (