From d6a56e8be29c1e8ea77d970434b8c441f23acdef Mon Sep 17 00:00:00 2001 From: Miqdad Date: Fri, 19 Sep 2025 17:16:54 +0700 Subject: add role --- app/lib/api/odooApi.ts | 61 +++++++++++++++++------------ app/lib/camera/component/dispatchCamera.tsx | 43 ++++++++++++++++++++ app/lib/camera/component/hedear.tsx | 37 ++++++++++++----- app/lib/camera/hooks/useCameraStore.ts | 4 ++ app/page.tsx | 31 +++++++++++++-- 5 files changed, 138 insertions(+), 38 deletions(-) create mode 100644 app/lib/camera/component/dispatchCamera.tsx diff --git a/app/lib/api/odooApi.ts b/app/lib/api/odooApi.ts index c2c9d82..fab3e0c 100644 --- a/app/lib/api/odooApi.ts +++ b/app/lib/api/odooApi.ts @@ -25,32 +25,43 @@ const getToken = async () => { return token }; -const odooApi = async (method : string, url : string, data = {}, headers = {}) => { - try { - const token = await getToken() - const auth = getAuth(); - const axiosParameter : axiosParameters = { - method, - url: process.env.NEXT_PUBLIC_ODOO_API_HOST + url, - headers: { Authorization: token ? token : '', ...headers }, - }; - console.log('ini adalah tipe',axiosParameter) - if (auth && typeof auth === 'object' && 'token' in auth) { - axiosParameter.headers['Token'] = auth.token; - } - if (method.toUpperCase() == 'POST') - axiosParameter.headers['Content-Type'] = - 'application/x-www-form-urlencoded'; - if (Object.keys(data).length > 0) - axiosParameter.data = new URLSearchParams( - Object.entries(data) - ).toString(); - const response = await axios(axiosParameter); - return response.data; - } catch (error) { - console.log( JSON.stringify(error)); +const odooApi = async (method: string, url: string, data = {}, headers = {}) => { + try { + const token = await getToken(); + const auth = getAuth(); + + const axiosParameter: axiosParameters = { + method, + url: process.env.NEXT_PUBLIC_ODOO_API_HOST + url, + headers: { Authorization: token ? token : '', ...headers }, + }; + + 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'; + } + + // Hanya kirim body untuk method yang memang pakai body + if (Object.keys(data).length > 0 && upper !== 'GET' && upper !== 'HEAD') { + const entries = Object.entries(data).filter( + ([, v]) => v !== undefined && v !== null && v !== '' + ) as [string, string][]; + axiosParameter.data = new URLSearchParams(entries).toString(); + } + + const response = await axios(axiosParameter); + return response.data; + } catch (error) { + console.log(JSON.stringify(error)); + } +}; + export default odooApi \ No newline at end of file diff --git a/app/lib/camera/component/dispatchCamera.tsx b/app/lib/camera/component/dispatchCamera.tsx new file mode 100644 index 0000000..2591413 --- /dev/null +++ b/app/lib/camera/component/dispatchCamera.tsx @@ -0,0 +1,43 @@ +import React from "react"; +import useCameraStore from "../hooks/useCameraStore"; +import { IconButton } from "@mui/material"; +import { LocalShipping } from "@mui/icons-material"; + +const DispatchCamera: React.FC = () => { + const { setImageDispatch } = useCameraStore(); + const handleCapture = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onloadend = () => { + setImageDispatch(reader.result as string); + }; + reader.readAsDataURL(file); + } + }; + + return ( +
+ + +
+ ); +}; + +export default DispatchCamera; diff --git a/app/lib/camera/component/hedear.tsx b/app/lib/camera/component/hedear.tsx index 2a8bfc6..81f5d01 100644 --- a/app/lib/camera/component/hedear.tsx +++ b/app/lib/camera/component/hedear.tsx @@ -1,36 +1,53 @@ // components/Header.tsx +"use client"; + import Image from "next/image"; import { deleteAuth, getAuth } from "../../api/auth"; import { Button } from "@mui/material"; import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; export default function Header() { - const auth = getAuth(); - const route = useRouter(); + const router = useRouter(); + const [mounted, setMounted] = useState(false); + const [auth, setAuth] = useState(null); + + useEffect(() => { + setMounted(true); + try { + setAuth(getAuth()); + } catch { + setAuth(null); + } + }, []); - const handleSigOut = () => { + const handleSignOut = () => { deleteAuth(); - route.push('/login'); + router.push("/login"); }; + return ( ); diff --git a/app/lib/camera/hooks/useCameraStore.ts b/app/lib/camera/hooks/useCameraStore.ts index c922d1c..359bcb3 100644 --- a/app/lib/camera/hooks/useCameraStore.ts +++ b/app/lib/camera/hooks/useCameraStore.ts @@ -8,6 +8,8 @@ interface CameraStore { setImageSj: (image: string) => void imagePackage: string | null setImagePackage: (image: string) => void + imageDispatch: string | null + setImageDispatch: (image: string) => void } const useCameraStore = create((set) => ({ @@ -17,6 +19,8 @@ const useCameraStore = create((set) => ({ setImageSj: (image: string) => set({ imageSj: image }), imagePackage: null, setImagePackage: (image: string) => set({ imagePackage: image }), + imageDispatch: null, + setImageDispatch: (image: string) => set({ imageDispatch: image }), })) export default useCameraStore \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index f12f746..363b6b6 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -3,6 +3,7 @@ import Image from "next/image"; import PackageCamera from "./lib/camera/component/pakageCamera"; import BarcodeScanner from "./lib/camera/component/scannerBarcode"; import SjCamera from "./lib/camera/component/sjCamera"; +import DispatchCamera from "./lib/camera/component/dispatchCamera"; import useCameraStore from "./lib/camera/hooks/useCameraStore"; import Header from "./lib/camera/component/hedear"; import { Button } from "@mui/material"; @@ -19,9 +20,11 @@ export default function Home() { barcode, imageSj, imagePackage, + imageDispatch, setBarcode, setImageSj, setImagePackage, + setImageDispatch, } = useCameraStore(); const [isLoading, setIsLoading] = useState(false); @@ -41,7 +44,7 @@ export default function Home() { event.preventDefault(); setIsLoading(true); - if (!barcode || !imageSj || !imagePackage) { + if (!barcode || !imageSj || !imagePackage || !imageDispatch) { alert("Barcode dan gambar harus tersedia."); setIsLoading(false); return; @@ -50,10 +53,12 @@ export default function Home() { try { const newSjImage = imageSj.replace(/^.*?,/, ""); const newPackageImage = imagePackage.replace(/^.*?,/, ""); + const newDispatchImage = imageDispatch.replace(/^.*?,/, ""); const data = { - sj_document: newSjImage, // Kirim base64 lengkap dengan prefix - paket_document: newPackageImage, // Kirim base64 lengkap dengan prefix + sj_document: newSjImage, + paket_document: newPackageImage, + dispatch_document: newDispatchImage, }; const response = await odooApi( @@ -66,6 +71,7 @@ export default function Home() { setBarcode(""); setImageSj(""); setImagePackage(""); + setImageDispatch(""); setIsLoading(false); }else if(response.status.code == 404){ alert("Gagal Submit Data, Picking Code Tidak Ditemukan " ); @@ -101,6 +107,7 @@ export default function Home() {
+
@@ -141,6 +148,24 @@ export default function Home() { )} +
+ {imageDispatch && ( + <> + +
+ Captured +
+ + )}