summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiqdad <ahmadmiqdad27@gmail.com>2025-09-20 09:27:05 +0700
committerMiqdad <ahmadmiqdad27@gmail.com>2025-09-20 09:27:05 +0700
commit5c3d6cfd6f68b6eb7192aba47463bd0541bfbf48 (patch)
treed1b8fac281e9d50c9a08e8d157e78c07714bca6b
parentd6a56e8be29c1e8ea77d970434b8c441f23acdef (diff)
<Miqdad> add role
-rw-r--r--app/lib/api/odooApi.ts55
-rw-r--r--app/lib/camera/hooks/useCameraStore.ts8
-rw-r--r--app/page.tsx95
3 files changed, 111 insertions, 47 deletions
diff --git a/app/lib/api/odooApi.ts b/app/lib/api/odooApi.ts
index fab3e0c..9ca6451 100644
--- a/app/lib/api/odooApi.ts
+++ b/app/lib/api/odooApi.ts
@@ -1,31 +1,31 @@
-import axios from "axios"
+import axios from "axios";
import { getCookie, setCookie } from "cookies-next";
import { getAuth } from "./auth";
type axiosParameters = {
- method : string,
- url : string,
- headers : {
- Authorization : string,
- 'Content-Type'? : string,
- Token? : string
- },
- data ?: string
-}
+ method: string;
+ url: string;
+ headers: {
+ Authorization: string;
+ "Content-Type"?: string;
+ Token?: string;
+ };
+ data?: string;
+};
const renewToken = async () => {
- const token = await axios.get(process.env.NEXT_PUBLIC_ODOO_API_HOST + '/api/token')
- setCookie('token', token.data.result)
- return token.data.result
+ const token = await axios.get(process.env.NEXT_PUBLIC_ODOO_API_HOST + "/api/token");
+ setCookie("token", token.data.result);
+ return token.data.result;
};
const getToken = async () => {
- let token = getCookie('token')
- if (token == undefined) token = await renewToken()
- return token
+ let token = getCookie("token") as string | undefined;
+ if (token == undefined) token = await renewToken();
+ return token;
};
-const odooApi = async (method: string, url: string, data = {}, headers = {}) => {
+const odooApi = async (method: string, url: string, data: Record<string, any> = {}, headers = {}) => {
try {
const token = await getToken();
const auth = getAuth();
@@ -33,24 +33,23 @@ const odooApi = async (method: string, url: string, data = {}, headers = {}) =>
const axiosParameter: axiosParameters = {
method,
url: process.env.NEXT_PUBLIC_ODOO_API_HOST + url,
- headers: { Authorization: token ? token : '', ...headers },
+ headers: { Authorization: token ? token : "", ...headers },
};
- if (auth && typeof auth === 'object' && 'token' in auth) {
- axiosParameter.headers['Token'] = (auth as any).token;
+ if (auth && typeof auth === "object" && "token" in auth) {
+ axiosParameter.headers["Token"] = (auth as any).token;
}
const upper = method.toUpperCase();
- // Set Content-Type untuk method yang kirim body
- if (upper === 'POST' || upper === 'PUT' || upper === 'PATCH') {
- axiosParameter.headers['Content-Type'] = 'application/x-www-form-urlencoded';
+ // Body methods
+ if (upper === "POST" || upper === "PUT" || upper === "PATCH") {
+ axiosParameter.headers["Content-Type"] = "application/x-www-form-urlencoded";
}
- // Hanya kirim body untuk method yang memang pakai body
- if (Object.keys(data).length > 0 && upper !== 'GET' && upper !== 'HEAD') {
+ if (Object.keys(data).length > 0 && upper !== "GET" && upper !== "HEAD") {
const entries = Object.entries(data).filter(
- ([, v]) => v !== undefined && v !== null && v !== ''
+ ([, v]) => v !== undefined && v !== null && v !== ""
) as [string, string][];
axiosParameter.data = new URLSearchParams(entries).toString();
}
@@ -62,6 +61,4 @@ const odooApi = async (method: string, url: string, data = {}, headers = {}) =>
}
};
-
-
-export default odooApi \ No newline at end of file
+export default odooApi;
diff --git a/app/lib/camera/hooks/useCameraStore.ts b/app/lib/camera/hooks/useCameraStore.ts
index 359bcb3..ad83074 100644
--- a/app/lib/camera/hooks/useCameraStore.ts
+++ b/app/lib/camera/hooks/useCameraStore.ts
@@ -13,13 +13,13 @@ interface CameraStore {
}
const useCameraStore = create<CameraStore>((set) => ({
- barcode: null,
+ barcode: '',
setBarcode: (barcode: string) => set({ barcode: barcode }),
- imageSj: null,
+ imageSj: '',
setImageSj: (image: string) => set({ imageSj: image }),
- imagePackage: null,
+ imagePackage: '',
setImagePackage: (image: string) => set({ imagePackage: image }),
- imageDispatch: null,
+ imageDispatch: '',
setImageDispatch: (image: string) => set({ imageDispatch: image }),
}))
diff --git a/app/page.tsx b/app/page.tsx
index 363b6b6..07a89f1 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -14,8 +14,51 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { getAuth } from "./lib/api/auth";
+// ====== ROLE EMAIL LISTS ======
+const DRIVER_EMAILS = new Set(
+ ["driverindoteknik@gmail.com", "sulistianaridwan8@gmail.com"]
+ .map(e => e.toLowerCase())
+);
+
+const DISPATCH_EMAILS = new Set(
+ ["rahmat.afiudin@gmail.com", "it@fixcomart.co.id"]
+ .map(e => e.toLowerCase())
+);
+
+function extractEmailFromAuth(auth: unknown): string | null {
+ if (auth && typeof auth === "object" && "email" in (auth as any)) {
+ const email = (auth as any).email;
+ if (typeof email === "string") return email;
+ }
+ if (auth && typeof auth === "object" && "token" in (auth as any)) {
+ const t = (auth as any).token;
+ if (typeof t === "string") {
+ const parts = t.split(".");
+ if (parts.length === 3) {
+ try {
+ const payload = JSON.parse(atob(parts[1]));
+ return payload?.email ?? payload?.preferred_username ?? payload?.sub ?? null;
+ } catch {}
+ }
+ }
+ }
+ if (typeof auth === "string") {
+ const parts = auth.split(".");
+ if (parts.length === 3) {
+ try {
+ const payload = JSON.parse(atob(parts[1]));
+ return payload?.email ?? payload?.preferred_username ?? payload?.sub ?? null;
+ } catch {}
+ }
+ }
+ return null;
+}
+
export default function Home() {
const [isLogin, setIsLogin] = useState<boolean>(true);
+ const [isDriver, setIsDriver] = useState<boolean>(false);
+ const [isDispatch, setIsDispatch] = useState<boolean>(false);
+
const {
barcode,
imageSj,
@@ -26,17 +69,28 @@ export default function Home() {
setImagePackage,
setImageDispatch,
} = useCameraStore();
- const [isLoading, setIsLoading] = useState<boolean>(false);
+ const [isLoading, setIsLoading] = useState<boolean>(false);
const router = useRouter();
useEffect(() => {
const token = getAuth();
+ console.log("FE auth (akan dipakai untuk header Token):", token);
if (!token) {
router.push("/login");
} else {
setIsLogin(true);
+
+ const email = extractEmailFromAuth(token);
+ const lower = (email ?? "").toLowerCase();
+
+ // PRIORITAS: dispatch > driver
+ const dispatchFlag = DISPATCH_EMAILS.has(lower);
+ const driverFlag = DRIVER_EMAILS.has(lower) && !dispatchFlag;
+
+ setIsDispatch(dispatchFlag);
+ setIsDriver(driverFlag);
}
}, [router]);
@@ -44,8 +98,15 @@ export default function Home() {
event.preventDefault();
setIsLoading(true);
- if (!barcode || !imageSj || !imagePackage || !imageDispatch) {
- alert("Barcode dan gambar harus tersedia.");
+ // Hanya role dispatch yang wajib foto Dispatch
+ const needDispatch = isDispatch;
+
+ if (!barcode || !imageSj || !imagePackage || (needDispatch && !imageDispatch)) {
+ alert(
+ needDispatch
+ ? "Barcode, Foto SJ, Foto Penerima, dan Foto Dispatch harus tersedia."
+ : "Barcode, Foto SJ, dan Foto Penerima harus tersedia."
+ );
setIsLoading(false);
return;
}
@@ -53,19 +114,22 @@ export default function Home() {
try {
const newSjImage = imageSj.replace(/^.*?,/, "");
const newPackageImage = imagePackage.replace(/^.*?,/, "");
- const newDispatchImage = imageDispatch.replace(/^.*?,/, "");
+ const newDispatchImage = imageDispatch ? imageDispatch.replace(/^.*?,/, "") : undefined;
- const data = {
- sj_document: newSjImage,
- paket_document: newPackageImage,
- dispatch_document: newDispatchImage,
+ const data: any = {
+ sj_document: newSjImage,
+ paket_document: newPackageImage,
};
+ if (!isDriver && newDispatchImage) {
+ data.dispatch_document = newDispatchImage;
+ }
const response = await odooApi(
"PUT",
`/api/v1/stock-picking/${barcode}/documentation`,
data
);
+
if (response.status.code == 200) {
alert("Berhasil Submit Data");
setBarcode("");
@@ -73,11 +137,11 @@ export default function Home() {
setImagePackage("");
setImageDispatch("");
setIsLoading(false);
- }else if(response.status.code == 404){
- alert("Gagal Submit Data, Picking Code Tidak Ditemukan " );
+ } else if (response.status.code == 404) {
+ alert("Gagal Submit Data, Picking Code Tidak Ditemukan ");
setIsLoading(false);
- }else{
- alert("Gagal Submit Data, Silahkan Coba Lagi" );
+ } else {
+ alert("Gagal Submit Data, Silahkan Coba Lagi");
setIsLoading(false);
}
return response.data;
@@ -107,7 +171,7 @@ export default function Home() {
<div className="flex justify-between">
<SjCamera />
<PackageCamera />
- <DispatchCamera />
+ {!isDriver && <DispatchCamera />} {/* disembunyikan untuk driver */}
</div>
<div className="h-2"></div>
@@ -148,8 +212,10 @@ export default function Home() {
</div>
</>
)}
+
<div className="h-2"></div>
- {imageDispatch && (
+
+ {!isDriver && imageDispatch && (
<>
<label className="block mt-2 text-sm font-medium text-gray-700 text-center">
Gambar Foto Dispatch
@@ -166,6 +232,7 @@ export default function Home() {
</div>
</>
)}
+
<div>
<div className="h-4"></div>
<Button