summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHATEC\SPVDEV001 <tri.susilo@altama.co.id>2023-09-02 10:37:04 +0700
committerHATEC\SPVDEV001 <tri.susilo@altama.co.id>2023-09-02 10:37:04 +0700
commit09996e253209cd6d163fa1b9a6667485b80dfa82 (patch)
tree78d33cc888b2433b5c0ac68fd0102de6c84a187a /src
parentbca256dfc413400a6c17ca189a8f31a15d82473a (diff)
parent6b1083de2c5ad57953c6653d00a42b2da3fea108 (diff)
Merge branch 'master' into CR/tampilan
Diffstat (limited to 'src')
-rw-r--r--src/core/components/elements/Navbar/NavbarDesktop.jsx9
-rw-r--r--src/core/components/elements/Navbar/NavbarUserDropdown.jsx9
-rw-r--r--src/core/components/layouts/BasicLayout.jsx5
-rw-r--r--src/core/utils/auth.js4
-rw-r--r--src/lib/auth/components/LoginDesktop.jsx57
-rw-r--r--src/lib/auth/components/LoginMobile.jsx57
-rw-r--r--src/lib/auth/components/Menu.jsx50
-rw-r--r--src/lib/auth/components/RegisterDesktop.jsx51
-rw-r--r--src/lib/auth/components/RegisterMobile.jsx50
-rw-r--r--src/lib/auth/hooks/useLogin.js19
-rw-r--r--src/lib/checkout/components/Checkout.jsx18
-rw-r--r--src/lib/shipment/api/listShipment.js9
-rw-r--r--src/lib/shipment/components/Shipments.jsx313
-rw-r--r--src/lib/transaction/components/Transaction.jsx53
-rw-r--r--src/lib/treckingAwb/api/getManifest.js9
-rw-r--r--src/lib/treckingAwb/component/Manifest.jsx177
-rw-r--r--src/pages/_app.jsx87
-rw-r--r--src/pages/api/auth/[...nextauth].js26
-rw-r--r--src/pages/my/menu.jsx61
-rw-r--r--src/pages/my/shipments/index.jsx29
20 files changed, 1006 insertions, 87 deletions
diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx
index 0aa9febf..655c4732 100644
--- a/src/core/components/elements/Navbar/NavbarDesktop.jsx
+++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx
@@ -10,15 +10,17 @@ import DesktopView from '../../views/DesktopView'
import dynamic from 'next/dynamic'
import IndoteknikLogo from '@/images/logo.png'
import Category from '@/lib/category/components/Category'
-import { useEffect, useState } from 'react'
+import { useContext, useEffect, useState } from 'react'
import useAuth from '@/core/hooks/useAuth'
import NavbarUserDropdown from './NavbarUserDropdown'
import { getCountCart } from '@/core/utils/cart'
import whatsappUrl from '@/core/utils/whatsappUrl'
import { useRouter } from 'next/router'
-import { getAuth } from '@/core/utils/auth'
+import { getAuth, setAuth } from '@/core/utils/auth'
import { createSlug, getIdFromSlug } from '@/core/utils/slug'
import productApi from '@/lib/product/api/productApi'
+import { useSession } from 'next-auth/react'
+import { AuthContext } from '@/pages/_app'
import { TopBannerSkeleton } from '../Skeleton/TopBannerSkeleton'
const Search = dynamic(() => import('./Search'))
@@ -28,6 +30,7 @@ const TopBanner = dynamic(() => import('./TopBanner'), {
const NavbarDesktop = () => {
const [isOpenCategory, setIsOpenCategory] = useState(false)
+ const {authenticated} = useContext(AuthContext)
const auth = useAuth()
const [cartCount, setCartCount] = useState(0)
@@ -37,7 +40,7 @@ const NavbarDesktop = () => {
const [urlPath, setUrlPath] = useState(null)
const router = useRouter()
-
+
useEffect(() => {
const handleCartChange = () => {
const cart = async () => {
diff --git a/src/core/components/elements/Navbar/NavbarUserDropdown.jsx b/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
index 7848124c..1851ce84 100644
--- a/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
+++ b/src/core/components/elements/Navbar/NavbarUserDropdown.jsx
@@ -1,13 +1,15 @@
import { deleteAuth } from '@/core/utils/auth'
import Link from '../Link/Link'
import { useRouter } from 'next/router'
+import { signOut, useSession } from 'next-auth/react'
const NavbarUserDropdown = () => {
const router = useRouter()
- const logout = () => {
- deleteAuth()
- router.push('/login')
+ const logout = async () => {
+ deleteAuth().then(() => {
+ router.push('/login')
+ })
}
return (
@@ -15,6 +17,7 @@ const NavbarUserDropdown = () => {
<div className='navbar-user-dropdown'>
<Link href='/my/quotations'>Daftar Quotation</Link>
<Link href='/my/transactions'>Daftar Transaksi</Link>
+ <Link href='/my/shipments'>Daftar Pengiriman</Link>
<Link href='/my/invoices'>Invoice & Faktur Pajak</Link>
<Link href='/my/wishlist'>Wishlist</Link>
<Link href='/my/address'>Daftar Alamat</Link>
diff --git a/src/core/components/layouts/BasicLayout.jsx b/src/core/components/layouts/BasicLayout.jsx
index f84cce40..266223d8 100644
--- a/src/core/components/layouts/BasicLayout.jsx
+++ b/src/core/components/layouts/BasicLayout.jsx
@@ -6,10 +6,11 @@ import { useEffect, useState } from 'react'
import axios from 'axios'
import odooApi from '@/core/api/odooApi'
import { useRouter } from 'next/router'
-import { getURL } from 'next/dist/shared/lib/utils'
import productApi from '@/lib/product/api/productApi'
-import { getAuth } from '@/core/utils/auth'
+import { getAuth, setAuth } from '@/core/utils/auth'
import { createSlug, getIdFromSlug } from '@/core/utils/slug'
+import { useSession } from 'next-auth/react'
+import { setCookie } from 'cookies-next'
const Navbar = dynamic(() => import('../elements/Navbar/Navbar'))
const AnimationLayout = dynamic(() => import('./AnimationLayout'))
diff --git a/src/core/utils/auth.js b/src/core/utils/auth.js
index cddff2b8..a7244747 100644
--- a/src/core/utils/auth.js
+++ b/src/core/utils/auth.js
@@ -1,4 +1,5 @@
import { deleteCookie, getCookie, setCookie } from 'cookies-next'
+import { signOut } from 'next-auth/react'
/**
* Retrieves authentication data from cookie and returns it as an object.
@@ -27,7 +28,8 @@ const setAuth = (user) => {
*
* @returns {boolean} - Returns `true`.
*/
-const deleteAuth = () => {
+const deleteAuth = async() => {
+ // await signOut()
deleteCookie('auth')
return true
}
diff --git a/src/lib/auth/components/LoginDesktop.jsx b/src/lib/auth/components/LoginDesktop.jsx
index 8ce2e4e3..838054cd 100644
--- a/src/lib/auth/components/LoginDesktop.jsx
+++ b/src/lib/auth/components/LoginDesktop.jsx
@@ -3,11 +3,46 @@ import useLogin from '../hooks/useLogin'
import Link from '@/core/components/elements/Link/Link'
import PageContent from '@/lib/content/components/PageContent'
import Alert from '@/core/components/elements/Alert/Alert'
+import { useSession, signIn, SignOut } from 'next-auth/react'
+import Image from 'next/image'
+import { useRouter } from 'next/router'
+import { useContext, useEffect, useState } from 'react'
+import { getAuth, setAuth } from '@/core/utils/auth'
+import { setCookie } from 'cookies-next'
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
+import Spinner from '@/core/components/elements/Spinner/Spinner'
+import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'
+import odooApi from '@/core/api/odooApi'
const LoginDesktop = () => {
- const { handleSubmit, handleChangeInput, isLoading, isValid, alert, emailRef, passwordRef } =
+ const { handleSubmit, handleChangeInput, isLoading, isValid, alert, emailRef, passwordRef, handleGoogleSubmit } =
useLogin()
+ const router = useRouter()
+ const [query, setQuery] = useState(router?.query?.next || '/')
+ const { data: session } = useSession()
+
+ const handleGoogle = async () => {
+ const url = query != '/' ? '/login?source=google&next=' + query : '/login?source=google'
+ await signIn('google', { callbackUrl: url })
+ }
+ useEffect(() => {
+ if (session) {
+ handleGoogleSubmit(session)
+ }
+ }, [session])
+
+ if (router.query.source) {
+ return (
+ <BottomPopup active={true} close=''>
+ <div className='leading-7 text-gray_r-12/80 flex justify-center'>Mohon Tunggu</div>
+ <div className='container flex justify-center my-4'>
+ <LogoSpinner width={48} height={48} />
+ </div>
+ </BottomPopup>
+ )
+ }
+
return (
<DesktopView>
<div className='container mx-auto'>
@@ -60,6 +95,26 @@ const LoginDesktop = () => {
{!isLoading ? 'Masuk' : 'Loading...'}
</button>
</form>
+ {/* <div className='flex items-center mt-3 mb-3'>
+ <hr className='flex-1' />
+ <p className='text-gray-400'>ATAU</p>
+ <hr className='flex-1' />
+ </div> */}
+
+ {/* <button
+ type='submit'
+ className='border border-gray-500 p-2 rounded-md hover:bg-gray-100 w-full mt-2 flex items-center justify-center gap-x-2'
+ onClick={() => handleGoogle()}
+ >
+ <Image
+ src='/images/icons8-google.svg'
+ alt='google image'
+ className='h-7 w-7'
+ width={10}
+ height={10}
+ />
+ <p>Masuk dengan Google</p>
+ </button> */}
<div className='text-gray_r-11 mt-10'>
Belum punya akun Indoteknik?{' '}
diff --git a/src/lib/auth/components/LoginMobile.jsx b/src/lib/auth/components/LoginMobile.jsx
index b365330b..2d6501cd 100644
--- a/src/lib/auth/components/LoginMobile.jsx
+++ b/src/lib/auth/components/LoginMobile.jsx
@@ -5,10 +5,45 @@ import Alert from '@/core/components/elements/Alert/Alert'
import MobileView from '@/core/components/views/MobileView'
import useLogin from '../hooks/useLogin'
+import { useSession, signIn, SignOut } from 'next-auth/react'
+import { useRouter } from 'next/router'
+import { useEffect, useState } from 'react'
+import { setCookie } from 'cookies-next'
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
+import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'
+import odooApi from '@/core/api/odooApi'
+import { getAuth } from '@/core/utils/auth'
+
const LoginMobile = () => {
- const { handleSubmit, handleChangeInput, isLoading, isValid, alert, emailRef, passwordRef } =
+ const { handleSubmit, handleChangeInput, isLoading, isValid, alert, emailRef, passwordRef, handleGoogleSubmit } =
useLogin()
+ const router = useRouter()
+ const [query, setQuery] = useState(router?.query?.next || '/')
+ const { data: session } = useSession()
+ const auth = getAuth()
+
+ const handleGoogle = async () => {
+ const url = query != '/' ? '/login?source=google&next=' + query : '/login?source=google'
+ await signIn('google', { callbackUrl: url })
+ }
+ useEffect(() => {
+ if (session) {
+ handleGoogleSubmit(session)
+ }
+ }, [session])
+
+ if (router.query.source) {
+ return (
+ <BottomPopup active={true} close={true}>
+ <div className='leading-7 text-gray_r-12/80 flex justify-center'>Mohon Tunggu</div>
+ <div className='container flex justify-center my-4'>
+ <LogoSpinner width={48} height={48} />
+ </div>
+ </BottomPopup>
+ )
+ }
+
return (
<MobileView>
<div className='p-6 pt-10 flex flex-col items-center min-h-screen'>
@@ -56,6 +91,26 @@ const LoginMobile = () => {
{!isLoading ? 'Masuk' : 'Loading...'}
</button>
</form>
+ {/* <div className='flex items-center mt-3 mb-3'>
+ <hr className='flex-1' />
+ <p className='text-gray-400'>ATAU</p>
+ <hr className='flex-1' />
+ </div> */}
+
+ {/* <button
+ type='submit'
+ className='border border-gray-500 p-2 rounded-md hover:bg-gray-100 w-full mt-2 flex items-center justify-center gap-x-2'
+ onClick={() => handleGoogle()}
+ >
+ <Image
+ src='/images/icons8-google.svg'
+ alt='google image'
+ className='h-7 w-7'
+ width={10}
+ height={10}
+ />
+ <p>Masuk dengan Google</p>
+ </button> */}
<div className='text-gray_r-11 mt-4'>
Belum punya akun Indoteknik?{' '}
diff --git a/src/lib/auth/components/Menu.jsx b/src/lib/auth/components/Menu.jsx
index 386b817c..939a0d5f 100644
--- a/src/lib/auth/components/Menu.jsx
+++ b/src/lib/auth/components/Menu.jsx
@@ -1,5 +1,6 @@
import Link from '@/core/components/elements/Link/Link'
import { useRouter } from 'next/router'
+import ImageNext from 'next/image'
const Menu = () => {
const router = useRouter()
@@ -10,30 +11,61 @@ const Menu = () => {
<div className='grid grid-cols-1 bg-white border border-gray_r-6 rounded py-2 px-4 sticky top-48'>
<div className='mt-4 mb-1 font-medium'>Menu</div>
<LinkItem href='/my/quotations' active={routeStartWith('/my/quotations')}>
- Daftar Quotation
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_daftar_quotation.svg' width={18} height={20} />
+ <p>Daftar Quotation</p>
+ </div>
</LinkItem>
<LinkItem href='/my/transactions' active={routeStartWith('/my/transactions')}>
- Daftar Transaksi
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_daftar_transaksi.svg' width={18} height={20} />
+ <p>Daftar Transaksi</p>
+ </div>
+ </LinkItem>
+ <LinkItem href='/my/shipments' active={routeStartWith('/my/shipments')}>
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_pengiriman.svg' width={18} height={20} />
+ <p>Daftar Pengiriman</p>
+ </div>
</LinkItem>
<LinkItem href='/my/invoices' active={routeStartWith('/my/invoices')}>
- Invoice & Faktur Pajak
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_invoice.svg' width={18} height={20} />
+ <p>Invoice & Faktur Pajak</p>
+ </div>
</LinkItem>
<LinkItem href='/my/wishlist' active={routeStartWith('/my/wishlist')}>
- Wishlist
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_wishlist.svg' width={18} height={20} />
+ <p>Wishlist</p>
+ </div>
</LinkItem>
-
<div className='mt-4 mb-1 font-medium'>Pusat Bantuan</div>
- <LinkItem href='/'>Layanan Pelanggan</LinkItem>
+ <LinkItem href='/'>
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_layanan_pelanggan.svg' width={18} height={20} />
+ <p>Layanan Pelanggan</p>
+ </div>
+ </LinkItem>
<div className='mt-4 mb-1 font-medium'>Pengaturan Akun</div>
<LinkItem href='/my/address' active={routeStartWith('/my/address')}>
- Daftar Alamat
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_daftar_alamat.svg' width={18} height={20} />
+ <p>Daftar Alamat</p>
+ </div>
</LinkItem>
<LinkItem href='/my/profile' active={routeStartWith('/my/profile')}>
- Profil Saya
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_profile.svg' width={18} height={20} />
+ <p>Profil Saya</p>
+ </div>
</LinkItem>
<button type='button' className='text-gray_r-12/80 p-2 text-left'>
- Keluar Akun
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_logout.svg' width={18} height={20} />
+ <p>Keluar Akun</p>
+ </div>
</button>
</div>
)
diff --git a/src/lib/auth/components/RegisterDesktop.jsx b/src/lib/auth/components/RegisterDesktop.jsx
index 93b505ab..6072bfb9 100644
--- a/src/lib/auth/components/RegisterDesktop.jsx
+++ b/src/lib/auth/components/RegisterDesktop.jsx
@@ -5,6 +5,12 @@ import Alert from '@/core/components/elements/Alert/Alert'
import PageContent from '@/lib/content/components/PageContent'
import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
import ReCAPTCHA from 'react-google-recaptcha'
+import Image from 'next/image'
+import { useEffect } from 'react'
+import { setCookie } from 'cookies-next'
+import { signIn, useSession } from 'next-auth/react'
+import { useRouter } from 'next/router'
+import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'
const RegisterDesktop = () => {
const {
@@ -21,6 +27,31 @@ const RegisterDesktop = () => {
tnd,
setTnd
} = useRegister()
+
+ const { data: session } = useSession()
+ const router = useRouter()
+
+ const handleGoogle = async () => {
+ await signIn('google', { callbackUrl: '/register?source=google' })
+ }
+
+ useEffect(() => {
+ if(session){
+ setCookie('auth', JSON.stringify(session?.odooUser))
+ router.push('/')
+ }
+ },[session])
+
+ if (router.query.source) {
+ return (
+ <BottomPopup active={true} close=''>
+ <div className='leading-7 text-gray_r-12/80 flex justify-center'>Mohon Tunggu</div>
+ <div className='container flex justify-center my-4'>
+ <LogoSpinner width={48} height={48} />
+ </div>
+ </BottomPopup>
+ )
+ }
return (
<DesktopView>
@@ -121,6 +152,26 @@ const RegisterDesktop = () => {
<PageContent path='/register#tnd'></PageContent>
</BottomPopup>
</div>
+ {/* <div className='flex items-center mt-3 mb-3'>
+ <hr className='flex-1' />
+ <p className='text-gray-400'>ATAU</p>
+ <hr className='flex-1' />
+ </div>
+
+ <button
+ type='submit'
+ className='border border-gray-500 p-2 rounded-md hover:bg-gray-100 w-full mt-2 flex items-center justify-center gap-x-2'
+ onClick={() => handleGoogle()}
+ >
+ <Image
+ src='/images/icons8-google.svg'
+ alt='google image'
+ className='h-7 w-7'
+ width={10}
+ height={10}
+ />
+ <p>Daftar dengan Google</p>
+ </button> */}
<div className='text-gray_r-11 mt-10'>
Sudah punya akun Indoteknik?{' '}
diff --git a/src/lib/auth/components/RegisterMobile.jsx b/src/lib/auth/components/RegisterMobile.jsx
index da6efaf5..1b0d2adf 100644
--- a/src/lib/auth/components/RegisterMobile.jsx
+++ b/src/lib/auth/components/RegisterMobile.jsx
@@ -7,6 +7,11 @@ import MobileView from '@/core/components/views/MobileView'
import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
import PageContent from '@/lib/content/components/PageContent'
import ReCAPTCHA from 'react-google-recaptcha'
+import { signIn, useSession } from 'next-auth/react'
+import { useRouter } from 'next/router'
+import { setCookie } from 'cookies-next'
+import { useEffect } from 'react'
+import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'
const RegisterMobile = () => {
const {
@@ -24,6 +29,30 @@ const RegisterMobile = () => {
setTnd
} = useRegister()
+ const { data: session } = useSession()
+ const router = useRouter()
+
+ const handleGoogle = async () => {
+ await signIn('google', { callbackUrl: '/register?source=google' })
+ }
+
+ useEffect(() => {
+ if(session){
+ setCookie('auth', JSON.stringify(session?.odooUser))
+ router.push('/')
+ }
+ },[session])
+
+ if (router.query.source) {
+ return (
+ <BottomPopup active={true} close=''>
+ <div className='leading-7 text-gray_r-12/80 flex justify-center'>Mohon Tunggu</div>
+ <div className='container flex justify-center my-4'>
+ <LogoSpinner width={48} height={48} />
+ </div>
+ </BottomPopup>
+ )
+ }
return (
<MobileView>
<div className='p-6 pt-10 flex flex-col items-center min-h-screen'>
@@ -122,6 +151,27 @@ const RegisterMobile = () => {
</BottomPopup>
</div>
+ {/* <div className='flex items-center mt-3 mb-3'>
+ <hr className='flex-1' />
+ <p className='text-gray-400'>ATAU</p>
+ <hr className='flex-1' />
+ </div>
+
+ <button
+ type='submit'
+ className='border border-gray-500 p-2 rounded-md hover:bg-gray-100 w-full mt-2 flex items-center justify-center gap-x-2'
+ onClick={() => handleGoogle()}
+ >
+ <Image
+ src='/images/icons8-google.svg'
+ alt='google image'
+ className='h-7 w-7'
+ width={10}
+ height={10}
+ />
+ <p>Daftar dengan Google</p>
+ </button> */}
+
<div className='text-gray_r-11 mt-4'>
Sudah punya akun Indoteknik?{' '}
<Link href='/login' className='inline'>
diff --git a/src/lib/auth/hooks/useLogin.js b/src/lib/auth/hooks/useLogin.js
index 1d5ff43d..34605614 100644
--- a/src/lib/auth/hooks/useLogin.js
+++ b/src/lib/auth/hooks/useLogin.js
@@ -3,6 +3,9 @@ import { setAuth } from '@/core/utils/auth'
import { useRouter } from 'next/router'
import { useRef, useState } from 'react'
import loginApi from '../api/loginApi'
+import odooApi from '@/core/api/odooApi'
+import { setCookie } from 'cookies-next'
+import { useSession } from 'next-auth/react'
const useLogin = () => {
const router = useRouter()
@@ -60,6 +63,19 @@ const useLogin = () => {
}
}
+ const handleGoogleSubmit = async (session) => {
+ const params = {
+ access_token: session.accessToken
+ }
+ const data = await odooApi('POST', '/api/v1/user/validate-sso', params)
+ if (data.isAuth) {
+ session.odooUser = data.user
+ setCookie('auth', JSON.stringify(session?.odooUser))
+ router.push(router?.query?.next ?? '/')
+ return
+ }
+ }
+
return {
handleChangeInput,
handleSubmit,
@@ -67,7 +83,8 @@ const useLogin = () => {
isValid,
alert,
emailRef,
- passwordRef
+ passwordRef,
+ handleGoogleSubmit
}
}
diff --git a/src/lib/checkout/components/Checkout.jsx b/src/lib/checkout/components/Checkout.jsx
index 27a00aa8..ce691403 100644
--- a/src/lib/checkout/components/Checkout.jsx
+++ b/src/lib/checkout/components/Checkout.jsx
@@ -297,10 +297,12 @@ const Checkout = () => {
order_line: JSON.stringify(productOrder),
delivery_amount: biayaKirim,
carrier_id: selectedCarrierId,
+ estimated_arrival_days: splitDuration(etd),
delivery_service_type: selectedExpedisiService,
voucher: activeVoucher,
type: 'sale_order'
}
+
if (query) {
data.source = 'buy'
}
@@ -1494,6 +1496,22 @@ function calculateEstimatedArrival(duration) {
return ''
}
+function splitDuration(duration){
+ if (duration) {
+ let estimationDate = null
+ if (duration.includes('-')){
+ estimationDate = duration.split('-')
+ estimationDate = parseInt(estimationDate[1])
+ }else{
+ estimationDate = parseInt(duration)
+ }
+
+ return estimationDate
+ }
+
+ return ''
+}
+
const extractDuration = (text) => {
const matches = text.match(/\d+(?:-\d+)?/g)
diff --git a/src/lib/shipment/api/listShipment.js b/src/lib/shipment/api/listShipment.js
new file mode 100644
index 00000000..a9237b76
--- /dev/null
+++ b/src/lib/shipment/api/listShipment.js
@@ -0,0 +1,9 @@
+import odooApi from "@/core/api/odooApi";
+import { getAuth } from "@/core/utils/auth"
+
+export const listShipments = async ({query}) => {
+ const auth = getAuth()
+ const list = await odooApi('GET', `/api/v1/partner/${auth.partnerId}/stock-picking?${query}`)
+
+ return list;
+}
diff --git a/src/lib/shipment/components/Shipments.jsx b/src/lib/shipment/components/Shipments.jsx
new file mode 100644
index 00000000..8b369a11
--- /dev/null
+++ b/src/lib/shipment/components/Shipments.jsx
@@ -0,0 +1,313 @@
+import DesktopView from '@/core/components/views/DesktopView'
+import MobileView from '@/core/components/views/MobileView'
+import Menu from '@/lib/auth/components/Menu'
+import { EllipsisVerticalIcon, MagnifyingGlassIcon } from '@heroicons/react/24/outline'
+import ImageNext from 'next/image'
+import { useRouter } from 'next/router'
+import { useQuery } from 'react-query'
+import _ from 'lodash-contrib'
+import Spinner from '@/core/components/elements/Spinner/Spinner'
+import Manifest from '@/lib/treckingAwb/component/Manifest'
+import { useState } from 'react'
+import Pagination from '@/core/components/elements/Pagination/Pagination'
+import Link from 'next/link'
+import TransactionStatusBadge from '@/lib/transaction/components/TransactionStatusBadge'
+
+const { listShipments } = require('../api/listShipment')
+
+const Shipments = () => {
+ const router = useRouter()
+ const { q = '', page = 1 } = router.query
+
+ const limit = 15
+
+ const query = {
+ q: q,
+ offset: (page - 1) * limit,
+ limit
+ }
+ const [inputQuery, setInputQuery] = useState(q)
+ const queryString = _.toQuery(query)
+
+ const { data: shipments } = useQuery('shipments', () => listShipments({ query: queryString }))
+ const [idAWB, setIdAWB] = useState(null)
+
+ const pageCount = Math.ceil(shipments?.pickingTotal / limit)
+ let pageQuery = _.omit(query, ['limit', 'offset', 'context'])
+ pageQuery = _.pickBy(pageQuery, _.identity)
+ pageQuery = _.toQuery(pageQuery)
+
+ const closePopup = () => {
+ setIdAWB(null)
+ }
+
+ const handleSubmit = async (e) => {
+ e.preventDefault()
+ router.push(`${router.pathname}?q=${inputQuery}`)
+ }
+ return (
+ <>
+ <MobileView>
+ <div className='p-4 flex flex-col gap-y-4'>
+ <div className='flex justify-between gap-x-1'>
+ <div className='flex justify-between items-center gap-x-2 p-2 bg-white border border-gray-200 rounded-lg shadow'>
+ <div>
+ <ImageNext src='/images/BOX(1).svg' width={15} height={20} />
+ </div>
+ <h1 className='text-xs'>Pending</h1>
+ <h1 className='text-xs'>
+ {' '}
+ {shipments?.summary?.pendingCount} {'>'}
+ </h1>
+ </div>
+ <div className='flex justify-between items-center gap-x-2 p-2 bg-white border border-gray-200 rounded-lg shadow'>
+ <div>
+ <ImageNext src='/images/BOX_DELIVER_(1).svg' width={18} height={20} />
+ </div>
+ <h1 className='text-xs'>Pengiriman</h1>
+ <h1 className='text-xs'>
+ {' '}
+ {shipments?.summary?.shipmentCount} {'>'}
+ </h1>
+ </div>
+ <div className='flex justify-between items-center gap-x-2 p-2 bg-white border border-gray-200 rounded-lg shadow'>
+ <div>
+ <ImageNext src='/images/open-box(1).svg' width={16} height={20} />
+ </div>
+ <h1 className='text-xs'>Selesai</h1>
+ <h1 className='text-xs'>
+ {' '}
+ {shipments?.summary?.shipmentCount} {'>'}
+ </h1>
+ </div>
+ </div>
+
+ <form className='flex gap-x-3' onSubmit={handleSubmit}>
+ <input
+ type='text'
+ className='form-input'
+ placeholder='Cari Pengiriman...'
+ value={inputQuery}
+ onChange={(e) => setInputQuery(e.target.value)}
+ />
+ <button className='btn-light bg-transparent px-3' type='submit'>
+ <MagnifyingGlassIcon className='w-6' />
+ </button>
+ </form>
+
+ {shipments?.pickings.map((shipment) => (
+ <div className='p-4 shadow border border-gray_r-3 rounded-md' key={shipment.id}>
+ <div className='flex justify-between items-center mb-3'>
+ <div className='text-caption-2 text-gray_r-11'>
+ <p>
+ Kurir :{' '}
+ <span className='text-gray_r-11 font-semibold'>
+ {shipment.carrierName || '-'}
+ </span>
+ </p>
+ <p className='mt-2'>No. Resi : {shipment.trackingNumber || '-'}</p>
+ </div>
+ <div className='flex justify-between'>
+ {shipment?.delivered && (
+ <div className='bg-green-100 p-2 rounded '>
+ <p className='text-green-600 text-sm'>Pesanan Tiba</p>
+ </div>
+ )}
+ {!shipment?.delivered && (
+ <div className='bg-red-100 p-2 rounded '>
+ <p className='text-red-600 text-sm'>Sedang Dikirim</p>
+ </div>
+ )}
+ </div>
+ </div>
+ <hr />
+ <div className='flex justify-between mt-2 items-center mb-5'>
+ <div>
+ <span className='text-caption-2 text-gray_r-11'>No. Transaksi</span>
+ <Link href={`/my/transactions/${shipment.saleOrder.id}`}>
+ <h2 className='text-danger-500 mt-1 mb-2'>{shipment.saleOrder.name}</h2>
+ </Link>
+ <span className='text-caption-2 text-gray_r-11'>{shipment.date}</span>
+ </div>
+ <div>
+ <button
+ onClick={() => setIdAWB(shipment.id)}
+ className='bg-red-600 p-2 border border-red-600 rounded text-white w-24'
+ >
+ {!shipment.delivered ? 'Lacak' : 'Histori'}
+ </button>
+ </div>
+ </div>
+ <hr />
+ <button
+ onClick={() => setIdAWB(shipment.id)}
+ className='flex items-center mt-1 gap-x-1 min-w-full'
+ >
+ <ImageNext src={`/images/BOX_DELIVERY_GREEN.svg`} width={20} height={20} />
+ <p className='text-sm text-green-700 truncate'>
+ {shipment.lastManifest.description}
+ </p>
+ <p className='ml-auto'>{'>'}</p>
+ </button>
+ </div>
+ ))}
+
+ <Pagination
+ pageCount={pageCount}
+ currentPage={parseInt(page)}
+ url={router.pathname + pageQuery}
+ className='mt-2 mb-2'
+ />
+ </div>
+
+ <Manifest idAWB={idAWB} closePopup={closePopup} />
+ </MobileView>
+ <DesktopView>
+ <div className='container mx-auto flex py-10'>
+ <div className='w-3/12 pr-4'>
+ <Menu />
+ </div>
+ <div className='w-9/12'>
+ <div className='p-4 bg-white border border-gray_r-6 rounded mb-2'>
+ <h1 className='text-title-sm font-semibold'>Pengiriman</h1>
+ <div
+ class='flex items-center p-4 mb-4 text-sm text-yellow-800 rounded-lg bg-yellow-50'
+ role='alert'
+ >
+ <svg
+ class='flex-shrink-0 inline w-4 h-4 mr-3'
+ aria-hidden='true'
+ fill='currentColor'
+ viewBox='0 0 20 20'
+ >
+ <path d='M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z' />
+ </svg>
+ <div>
+ Lacak pengiriman untuk setiap transaksi anda semakin mudah di Indoteknik.com
+ </div>
+ </div>
+ <div className='flex justify-between gap-x-5'>
+ <div class='max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow min-w-[268px]'>
+ <h2 class='mb-2 text-lg font-bold tracking-tight'>Pending</h2>
+ <div className='bg-red-100 border border-red-200 rounded-sm p-2 w-20 h-[39px] mb-2'>
+ <div>
+ <ImageNext
+ src='/images/BOX(1).svg'
+ width={25}
+ height={20}
+ style={{ stroke: 'red' }}
+ />
+ </div>
+ </div>
+ <h1 className='text-xl font-bold'>
+ {shipments?.summary?.pendingCount} <span className='text-sm'>Pesanan</span>
+ </h1>
+ </div>
+ <div class='max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow min-w-[268px]'>
+ <h5 class='mb-2 text-lg font-bold tracking-tight'>Pengiriman</h5>
+ <div className='bg-yellow-100 border border-yellow-200 rounded-sm p-1 w-20 mb-2'>
+ <div>
+ <ImageNext src='/images/BOX_DELIVER_(1).svg' width={30} height={20} />
+ </div>
+ </div>
+ <h1 className='text-xl font-bold'>
+ {shipments?.summary?.shipmentCount} <span className='text-sm'>Pesanan</span>
+ </h1>
+ </div>
+ <div class='max-w-sm p-6 bg-white border border-gray-200 rounded-lg shadow min-w-[268px]'>
+ <h5 class='mb-2 text-lg font-bold tracking-tight'>Pesanan Tiba</h5>
+ <div className='bg-green-100 border border-green-200 rounded-sm p-1 w-20 mb-2'>
+ <div>
+ <ImageNext
+ src='/images/open-box(1).svg'
+ width={30}
+ height={20}
+ className='stroke-orange-600'
+ />
+ </div>
+ </div>
+ <h1 className='text-xl font-bold'>
+ {shipments?.summary?.completedCount} <span className='text-sm'>Pesanan</span>
+ </h1>
+ </div>
+ </div>
+ </div>
+ <div className='p-4 bg-white border border-gray_r-6 rounded'>
+ <div className='flex mb-6 items-center justify-between'>
+ <h1 className='text-title-sm font-semibold'>Detail Pengiriman</h1>
+ <form className='flex gap-x-2' onSubmit={handleSubmit}>
+ <input
+ type='text'
+ className='form-input'
+ placeholder='Cari Pengiriman...'
+ value={inputQuery}
+ onChange={(e) => setInputQuery(e.target.value)}
+ />
+ <button className='btn-light bg-transparent px-3' type='submit'>
+ <MagnifyingGlassIcon className='w-6' />
+ </button>
+ </form>
+ </div>
+ <table className='table-data'>
+ <thead>
+ <tr>
+ <th>Tanggal</th>
+ <th>No. Resi</th>
+ <th>No. Pengiriman</th>
+ <th>Sales Order</th>
+ <th>Purchase Order</th>
+ <th>Expedisi</th>
+ <th>Status</th>
+ </tr>
+ </thead>
+ <tbody>
+ {!shipments && (
+ <tr>
+ <td colSpan={7}>
+ <div className='flex justify-center my-2'>
+ <Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12' />
+ </div>
+ </td>
+ </tr>
+ )}
+ {shipments && shipments?.pickings?.length == 0 && (
+ <tr>
+ <td colSpan={7}>Tidak ada transaksi</td>
+ </tr>
+ )}
+ {shipments?.pickings.map((shipment) => (
+ <tr key={shipment.id}>
+ <td>{shipment.date || '-'}</td>
+ <td>{shipment.trackingNumber || '-'}</td>
+ <td>{shipment.name || '-'}</td>
+ <td>{shipment.saleOrder.name || '-'}</td>
+ <td>{shipment.saleOrder.clientOrderRef || '-'}</td>
+ <td>{shipment.carrierName || '-'}</td>
+ <td>
+ <button
+ onClick={() => setIdAWB(shipment.id)}
+ className='bg-red-600 border border-red-600 rounded-md text-sm text-white p-1 w-20'
+ >
+ Lacak
+ </button>
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ <Pagination
+ pageCount={pageCount}
+ currentPage={parseInt(page)}
+ url={router.pathname + pageQuery}
+ className='mt-2 mb-2'
+ />
+ </div>
+ </div>
+ </div>
+ <Manifest idAWB={idAWB} closePopup={closePopup} />
+ </DesktopView>
+ </>
+ )
+}
+
+export default Shipments
diff --git a/src/lib/transaction/components/Transaction.jsx b/src/lib/transaction/components/Transaction.jsx
index 74f3dbd5..82eb1775 100644
--- a/src/lib/transaction/components/Transaction.jsx
+++ b/src/lib/transaction/components/Transaction.jsx
@@ -21,6 +21,7 @@ import Image from '@/core/components/elements/Image/Image'
import { createSlug } from '@/core/utils/slug'
import toTitleCase from '@/core/utils/toTitleCase'
import useAirwayBill from '../hooks/useAirwayBill'
+import Manifest from '@/lib/treckingAwb/component/Manifest'
const Transaction = ({ id }) => {
const { transaction } = useTransaction({ id })
@@ -31,6 +32,7 @@ const Transaction = ({ id }) => {
const poNumber = useRef(null)
const poFile = useRef(null)
const [uploadPo, setUploadPo] = useState(false)
+ const [idAWB, setIdAWB] = useState(null)
const openUploadPo = () => setUploadPo(true)
const closeUploadPo = () => setUploadPo(false)
const submitUploadPo = async () => {
@@ -110,6 +112,10 @@ const Transaction = ({ id }) => {
)
}
+ const closePopup = () => {
+ setIdAWB(null)
+ }
+
return (
transaction.data?.name && (
<>
@@ -158,6 +164,7 @@ const Transaction = ({ id }) => {
</button>
</div>
</BottomPopup>
+ <Manifest idAWB={idAWB} closePopup={closePopup}></Manifest>
<MobileView>
<div className='flex flex-col gap-y-4 p-4'>
@@ -179,26 +186,28 @@ const Transaction = ({ id }) => {
<div className='p-4'>
<div className='font-medium'>Pengiriman</div>
<div className='flex flex-col gap-y-3 mt-4'>
- {queryAirwayBill.data?.airways?.map((airway) => (
+ {transaction?.data?.pickings?.map((airway) => (
<button
- className='shadow rounded-md p-4 text-gray_r-12 font-normal flex justify-between items-center text-left'
- key={airway?.waybillNumber}
- onClick={() => setAirwayBillPopup(airway?.waybillNumber)}
+ className='shadow rounded-md p-3 text-gray_r-12 font-normal flex justify-between items-center text-left'
+ key={airway?.id}
+ onClick={() => setIdAWB(airway?.id)}
>
<div>
- <span className='text-sm text-gray_r-11'>No Resi</span>
- <p className='mt-1 font-medium'>{airway?.waybillNumber}</p>
+ <span className='text-sm text-gray_r-11'>
+ No Resi : {airway?.trackingNumber || '-'}{' '}
+ </span>
+ <p className='mt-1 font-medium'>{airway?.name}</p>
</div>
<div className='flex gap-x-2'>
- <div className='text-sm text-gray_r-11 badge-green'>
- {airway?.deliveryStatus?.status}
+ <div className='text-sm text-gray-600 badge-green leading-[1.5] mt-1'>
+ {airway?.delivered ? 'Pesanan Tiba' : 'Sedang Dikirim'}
</div>
<ChevronRightIcon className='w-5 stroke-2' />
</div>
</button>
))}
</div>
- {!queryAirwayBill?.data?.airways && (
+ {transaction?.data?.pickings == 0 && (
<div className='badge-red text-sm px-2'>Belum ada pengiriman</div>
)}
</div>
@@ -368,27 +377,29 @@ const Transaction = ({ id }) => {
</div>
<div className='text-h-sm font-semibold mt-10 mb-4'>Pengiriman</div>
- <div className='grid grid-cols-3 gap-4'>
- {queryAirwayBill.data?.airways?.map((airway) => (
+ <div className='grid grid-cols-3 gap-1'>
+ {transaction?.data?.pickings?.map((airway) => (
<button
- className='shadow rounded-md p-4 text-gray_r-12 font-normal flex justify-between items-center text-left'
- key={airway?.waybillNumber}
- onClick={() => setAirwayBillPopup(airway?.waybillNumber)}
+ className='shadow rounded-md p-3 text-gray_r-12 font-normal flex justify-between items-center text-left'
+ key={airway?.id}
+ onClick={() => setIdAWB(airway?.id)}
>
<div>
- <span className='text-sm text-gray_r-11'>No Resi</span>
- <p className='mt-1 font-medium'>{airway?.waybillNumber}</p>
+ <span className='text-sm text-gray_r-11'>
+ No Resi : {airway?.trackingNumber || '-'}{' '}
+ </span>
+ <p className='mt-1 font-medium'>{airway?.name}</p>
</div>
<div className='flex gap-x-2'>
- <div className='text-sm text-gray_r-11 badge-green'>
- {airway?.deliveryStatus?.status}
+ <div className='text-sm text-gray-600 badge-green leading-[1.5] mt-1'>
+ {airway?.delivered ? 'Pesanan Tiba' : 'Sedang Dikirim'}
</div>
<ChevronRightIcon className='w-5 stroke-2' />
</div>
</button>
))}
</div>
- {!queryAirwayBill.data?.airways && (
+ {transaction?.data?.pickings.length == 0 && (
<div className='badge-red text-sm'>Belum ada pengiriman</div>
)}
@@ -514,7 +525,7 @@ const Transaction = ({ id }) => {
</div>
</DesktopView>
- {queryAirwayBill.data?.airways?.map((airway) => (
+ {/* {queryAirwayBill.data?.airways?.map((airway) => (
<BottomPopup
key={airway.waybillNumber}
title='Detail Pengiriman'
@@ -564,7 +575,7 @@ const Transaction = ({ id }) => {
</ol>
</div>
</BottomPopup>
- ))}
+ ))} */}
</>
)
)
diff --git a/src/lib/treckingAwb/api/getManifest.js b/src/lib/treckingAwb/api/getManifest.js
new file mode 100644
index 00000000..7d78a5f2
--- /dev/null
+++ b/src/lib/treckingAwb/api/getManifest.js
@@ -0,0 +1,9 @@
+const { default: odooApi } = require("@/core/api/odooApi")
+const { getAuth } = require("@/core/utils/auth")
+
+export const getManifest = async ({id}) => {
+ const auth = getAuth()
+ const manifest = await odooApi('GET', `/api/v1/partner/${auth.partnerId}/stock-picking/${id}/tracking`)
+
+ return manifest
+} \ No newline at end of file
diff --git a/src/lib/treckingAwb/component/Manifest.jsx b/src/lib/treckingAwb/component/Manifest.jsx
new file mode 100644
index 00000000..185a9d55
--- /dev/null
+++ b/src/lib/treckingAwb/component/Manifest.jsx
@@ -0,0 +1,177 @@
+import odooApi from '@/core/api/odooApi'
+import BottomPopup from '@/core/components/elements/Popup/BottomPopup'
+import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'
+import { getAuth } from '@/core/utils/auth'
+import { useEffect, useState } from 'react'
+import { toast } from 'react-hot-toast'
+import ImageNext from 'next/image'
+
+const Manifest = ({ idAWB, closePopup }) => {
+ const [manifests, setManifests] = useState(null)
+ const [isLoading, setIsLoading] = useState(false)
+
+ const formatCustomDate = (date) => {
+ const months = [
+ 'Jan',
+ 'Feb',
+ 'Mar',
+ 'Apr',
+ 'May',
+ 'Jun',
+ 'Jul',
+ 'Aug',
+ 'Sep',
+ 'Oct',
+ 'Nov',
+ 'Dec'
+ ]
+
+ const parts = date.split(' ') // Pisahkan tanggal dan waktu
+ const [datePart, timePart] = parts
+ const [yyyy, mm, dd] = datePart.split('-')
+ const [hh, min] = timePart.split(':')
+
+ const monthAbbreviation = months[parseInt(mm, 10) - 1]
+
+ return `${dd} ${monthAbbreviation} ${hh}:${min}`
+ }
+
+ const getManifest = async () => {
+ setIsLoading(true)
+ const auth = getAuth()
+ const list = await odooApi(
+ 'GET',
+ `/api/v1/partner/${auth.partnerId}/stock-picking/${idAWB}/tracking`
+ )
+ setManifests(list)
+ setIsLoading(false)
+ }
+
+ useEffect(() => {
+ if (idAWB) {
+ getManifest()
+ } else {
+ setManifests(null)
+ }
+ }, [idAWB])
+
+ const [copied, setCopied] = useState(false)
+
+ const handleCopyClick = () => {
+ const textToCopy = manifests?.waybillNumber
+ navigator.clipboard.writeText(textToCopy)
+ setCopied(true)
+ toast.success('No Resi Berhasil di Copy')
+ setTimeout(() => setCopied(false), 2000) // Reset copied state after 2 seconds
+ }
+
+ return (
+ <>
+ {isLoading && (
+ <BottomPopup active={true} close=''>
+ <div className='leading-7 text-gray_r-12/80 flex justify-center'>Mohon Tunggu</div>
+ <div className='container flex justify-center my-4'>
+ <LogoSpinner width={48} height={48} />
+ </div>
+ </BottomPopup>
+ )}
+ {!isLoading && (
+ <BottomPopup
+ key={manifests?.waybillNumber}
+ title='Detail Pengiriman'
+ active={idAWB}
+ close={closePopup}
+ >
+ <div className='flex justify-between items-center mb-5'>
+ <h1 className='text-body-1'>Status Pesanan</h1>
+ {manifests?.delivered && (
+ <div className='bg-green-100 p-2 rounded '>
+ <p className='text-green-600 text-sm'>Pesanan Tiba</p>
+ </div>
+ )}
+ {!manifests?.delivered && (
+ <div className='bg-red-100 p-2 rounded '>
+ <p className='text-red-600 text-sm'>Sedang Dikirim</p>
+ </div>
+ )}
+ </div>
+ <div className=''>
+ <h1 className='text-body-1'>
+ Estimasi tiba pada <span className='text-gray_r-11 text-sm'>({manifests?.eta})</span>
+ </h1>
+ <h1 className='text-sm mt-2 mb-3'>
+ Dikirim Menggunakan{' '}
+ <span className='text-red-500 font-semibold'>{manifests?.deliveryOrder.carrier}</span>
+ </h1>
+ {manifests?.waybillNumber && (
+ <div className='flex justify-between items-center'>
+ <h1>No. Resi</h1>
+ <div className='flex justify-between gap-x-2 items-center'>
+ <h1 className='font-semibold'>{manifests?.waybillNumber}</h1>
+ <button
+ className={`${copied ? 'text-gray-400' : 'text-red-600 '}`}
+ onClick={() => handleCopyClick()}
+ >
+ <svg
+ aria-hidden='true'
+ fill='none'
+ stroke='currentColor'
+ stroke-width='1.5'
+ viewBox='0 0 24 24'
+ className='w-5 h-6'
+ >
+ <path
+ d='M15.75 17.25v3.375c0 .621-.504 1.125-1.125 1.125h-9.75a1.125 1.125 0 01-1.125-1.125V7.875c0-.621.504-1.125 1.125-1.125H6.75a9.06 9.06 0 011.5.124m7.5 10.376h3.375c.621 0 1.125-.504 1.125-1.125V11.25c0-4.46-3.243-8.161-7.5-8.876a9.06 9.06 0 00-1.5-.124H9.375c-.621 0-1.125.504-1.125 1.125v3.5m7.5 10.375H9.375a1.125 1.125 0 01-1.125-1.125v-9.25m12 6.625v-1.875a3.375 3.375 0 00-3.375-3.375h-1.5a1.125 1.125 0 01-1.125-1.125v-1.5a3.375 3.375 0 00-3.375-3.375H9.75'
+ stroke-linecap='round'
+ stroke-linejoin='round'
+ ></path>
+ </svg>
+ </button>
+ </div>
+ </div>
+ )}
+ </div>
+ <hr className='mt-4' />
+ <div className='pt-4'>
+ <ol class='relative border-l border-gray_r-7'>
+ {manifests?.manifests?.map((manifest, index) => (
+ <>
+ <li class='mb-6 ml-4' key={index}>
+ {manifests.delivered == true && index == 0 ? (
+ <div
+ class={`absolute w-6 h-6 rounded-full mt-1.5 -left-3 border ${
+ index == 0 ? 'bg-green-100 border-green-100' : 'bg-gray_r-7 border-white'
+ }`}
+ >
+ <ImageNext src='/images/open-box(1).svg' width={30} height={20} />
+ </div>
+ ) : (
+ <div
+ class={`absolute w-3 h-3 rounded-full mt-1.5 -left-1.5 border bg-gray_r-7 border-white`}
+ />
+ )}
+ {manifests.delivered != true && (
+ <div
+ class={`absolute w-3 h-3 rounded-full mt-1.5 -left-1.5 border ${index == 0 ? 'bg-green-600 border-green-600' : 'bg-gray_r-7 border-white'} `}
+ />
+ )}
+
+ <time class='text-sm leading-none text-gray-400'>
+ {formatCustomDate(manifest.datetime)}
+ </time>
+ {manifests.delivered == true && index == 0 && (
+ <p class={`leading-6 font-semibold text-sm text-green-600 `}>Sudah Sampai</p>
+ )}
+ <p class={`leading-6 text-[12px] text-gray_r-11`}>{manifest.description}</p>
+ </li>
+ </>
+ ))}
+ </ol>
+ </div>
+ </BottomPopup>
+ )}
+ </>
+ )
+}
+
+export default Manifest
diff --git a/src/pages/_app.jsx b/src/pages/_app.jsx
index 03147219..7f23b94b 100644
--- a/src/pages/_app.jsx
+++ b/src/pages/_app.jsx
@@ -6,16 +6,29 @@ import { AnimatePresence, motion } from 'framer-motion'
import { Toaster } from 'react-hot-toast'
import { QueryClient, QueryClientProvider } from 'react-query'
import useDevice from '@/core/hooks/useDevice'
-import { useEffect, useState } from 'react'
+import { createContext, useContext, useEffect, useState } from 'react'
import LogoSpinner from '@/core/components/elements/Spinner/LogoSpinner'
+import { SessionProvider } from 'next-auth/react'
+import { getAuth } from '@/core/utils/auth'
const queryClient = new QueryClient()
-function MyApp({ Component, pageProps }) {
+export const AuthContext = createContext({
+ authenticated : false,
+ setAuthenticated : (auth) => {}
+})
+
+function MyApp({ Component, pageProps: { session, ...pageProps } }) {
const router = useRouter()
const { isMobile } = useDevice()
const [animateLoader, setAnimateLoader] = useState(false)
+ const [authenticated, setAuthenticated] = useState(null)
+ const auth = getAuth()
+
+ // useEffect(() => {
+ // setAuthenticated(auth)
+ // }, [auth])
useEffect(() => {
const handleRouteChangeStart = () => setAnimateLoader(true)
@@ -48,41 +61,43 @@ function MyApp({ Component, pageProps }) {
}, [isMobile])
return (
- <>
- <AnimatePresence>
- {animateLoader && (
- <motion.div
- initial={{ opacity: 0 }}
- animate={{ opacity: 1 }}
- exit={{ opacity: 0 }}
- transition={{
- duration: 0.1
- }}
- className='fixed w-screen h-screen z-[500] bg-white flex justify-center items-center'
- >
- <LogoSpinner />
- </motion.div>
- )}
- </AnimatePresence>
- <Toaster
- position='top-center'
- containerStyle={toasterStyle}
- toastOptions={{
- duration: 3000,
- className: 'border border-gray_r-8'
- }}
- />
- <NextProgress color='#F01C21' options={{ showSpinner: false }} />
- <QueryClientProvider client={queryClient}>
- <AnimatePresence
- mode='popLayout'
- initial={false}
- onExitComplete={() => window.scrollTo(0, 0)}
- >
- {!animateLoader && <Component {...pageProps} key={router.asPath} />}
+ // <AuthContext.Provider value={{authenticated, setAuthenticated}}>
+ <SessionProvider session={session}>
+ <AnimatePresence>
+ {animateLoader && (
+ <motion.div
+ initial={{ opacity: 0 }}
+ animate={{ opacity: 1 }}
+ exit={{ opacity: 0 }}
+ transition={{
+ duration: 0.1
+ }}
+ className='fixed w-screen h-screen z-[500] bg-white flex justify-center items-center'
+ >
+ <LogoSpinner />
+ </motion.div>
+ )}
</AnimatePresence>
- </QueryClientProvider>
- </>
+ <Toaster
+ position='top-center'
+ containerStyle={toasterStyle}
+ toastOptions={{
+ duration: 3000,
+ className: 'border border-gray_r-8'
+ }}
+ />
+ <NextProgress color='#F01C21' options={{ showSpinner: false }} />
+ <QueryClientProvider client={queryClient}>
+ <AnimatePresence
+ mode='popLayout'
+ initial={false}
+ onExitComplete={() => window.scrollTo(0, 0)}
+ >
+ {!animateLoader && <Component {...pageProps} key={router.asPath} />}
+ </AnimatePresence>
+ </QueryClientProvider>
+ </SessionProvider>
+ // </AuthContext.Provider>
)
}
diff --git a/src/pages/api/auth/[...nextauth].js b/src/pages/api/auth/[...nextauth].js
new file mode 100644
index 00000000..3c433167
--- /dev/null
+++ b/src/pages/api/auth/[...nextauth].js
@@ -0,0 +1,26 @@
+import odooApi from '@/core/api/odooApi'
+import NextAuth from 'next-auth/next'
+import GoogleProvider from 'next-auth/providers/google'
+
+export default NextAuth({
+ providers: [
+ GoogleProvider({
+ clientId: process.env.GOOGLE_CLIENT_ID,
+ clientSecret: process.env.GOOGLE_CLIENT_SECRET
+ })
+ ],
+ callbacks: {
+ async jwt({ token, account }) {
+ if (account) {
+ token.accessToken = account.access_token
+ }
+ return token
+ },
+ async session({ session, token, user }) {
+ session.accessToken = token.accessToken
+
+ return session
+ }
+ },
+ secret: process.env.JWT_SECRET
+})
diff --git a/src/pages/my/menu.jsx b/src/pages/my/menu.jsx
index c8e1e7e9..a0ce223e 100644
--- a/src/pages/my/menu.jsx
+++ b/src/pages/my/menu.jsx
@@ -5,15 +5,19 @@ import useAuth from '@/core/hooks/useAuth'
import { deleteAuth } from '@/core/utils/auth'
import IsAuth from '@/lib/auth/components/IsAuth'
import { ChevronRightIcon, UserIcon } from '@heroicons/react/24/solid'
+import { signOut, useSession } from 'next-auth/react'
import { useRouter } from 'next/router'
+import ImageNext from 'next/image'
export default function Menu() {
const auth = useAuth()
const router = useRouter()
+ const { data: session } = useSession()
const logout = () => {
- deleteAuth()
- router.push('/login')
+ deleteAuth().then(() => {
+ router.push('/login')
+ })
}
return (
@@ -40,10 +44,38 @@ export default function Menu() {
<MenuHeader>Aktivitas Pembelian</MenuHeader>
<div className='divide-y divide-gray_r-6 border-y border-gray_r-6 mt-4'>
- <LinkItem href='/my/quotations'>Daftar Quotation</LinkItem>
- <LinkItem href='/my/transactions'>Daftar Transaksi</LinkItem>
- <LinkItem href='/my/invoices'>Invoice & Faktur Pajak</LinkItem>
- <LinkItem href='/my/wishlist'>Wishlist</LinkItem>
+ <LinkItem href='/my/quotations'>
+ {' '}
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_daftar_quotation.svg' width={18} height={20} />
+ <p>Daftar Quotation</p>
+ </div>
+ </LinkItem>
+ <LinkItem href='/my/transactions'>
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_daftar_transaksi.svg' width={18} height={20} />
+ <p>Daftar Transaksi</p>
+ </div>
+ </LinkItem>
+ <LinkItem href='/my/shipments'>
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_pengiriman.svg' width={18} height={20} />
+ <p>Daftar Pengiriman</p>
+ </div>
+ </LinkItem>
+ <LinkItem href='/my/invoices'>
+ {' '}
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_invoice.svg' width={18} height={20} />
+ <p>Invoice & Faktur Pajak</p>
+ </div>
+ </LinkItem>
+ <LinkItem href='/my/wishlist'>
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_wishlist.svg' width={18} height={20} />
+ <p>Wishlist</p>
+ </div>
+ </LinkItem>
</div>
</div>
@@ -51,7 +83,13 @@ export default function Menu() {
<MenuHeader>Pusat Bantuan</MenuHeader>
<div className='divide-y divide-gray_r-6 border-y border-gray_r-6 mt-4'>
- <LinkItem href='/'>Layanan Pelanggan</LinkItem>
+ <LinkItem href='/'>
+ {' '}
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_layanan_pelanggan.svg' width={18} height={20} />
+ <p>Layanan Pelanggan</p>
+ </div>
+ </LinkItem>
</div>
</div>
@@ -59,10 +97,15 @@ export default function Menu() {
<MenuHeader>Pengaturan Akun</MenuHeader>
<div className='divide-y divide-gray_r-6 border-y border-gray_r-6 mt-4'>
- <LinkItem href='/my/address'>Daftar Alamat</LinkItem>
+ <LinkItem href='/my/address'>
+ <div className='flex gap-x-3 items-center'>
+ <ImageNext src='/images/icon/icon_daftar_alamat.svg' width={18} height={20} />
+ <p>Daftar Alamat</p>
+ </div>
+ </LinkItem>
</div>
- <div onClick={logout} className='p-4 mt-2'>
+ <div onClick={() => logout()} className='p-4 mt-2'>
<button className='w-full btn-red'>Keluar Akun</button>
</div>
</div>
diff --git a/src/pages/my/shipments/index.jsx b/src/pages/my/shipments/index.jsx
new file mode 100644
index 00000000..cb69c4e9
--- /dev/null
+++ b/src/pages/my/shipments/index.jsx
@@ -0,0 +1,29 @@
+import Seo from '@/core/components/Seo'
+import AppLayout from '@/core/components/layouts/AppLayout'
+import BasicLayout from '@/core/components/layouts/BasicLayout'
+import DesktopView from '@/core/components/views/DesktopView'
+import MobileView from '@/core/components/views/MobileView'
+import IsAuth from '@/lib/auth/components/IsAuth'
+import dynamic from 'next/dynamic'
+
+const ShipmentsComponent = dynamic(() => import('@/lib/shipment/components/Shipments'))
+
+export default function MyShipments() {
+ return (
+ <IsAuth>
+ <Seo title='Shipments - Indoteknik.com' />
+
+ <MobileView>
+ <AppLayout title='Pengiriman'>
+ <ShipmentsComponent />
+ </AppLayout>
+ </MobileView>
+
+ <DesktopView>
+ <BasicLayout>
+ <ShipmentsComponent />
+ </BasicLayout>
+ </DesktopView>
+ </IsAuth>
+ )
+}