diff options
Diffstat (limited to 'src-migrate')
| -rw-r--r-- | src-migrate/modules/cart/components/Item.tsx | 20 | ||||
| -rw-r--r-- | src-migrate/modules/product-detail/components/AddToCart.tsx | 37 | ||||
| -rw-r--r-- | src-migrate/modules/product-detail/components/PriceAction.tsx | 2 | ||||
| -rw-r--r-- | src-migrate/modules/product-detail/components/ProductDetail.tsx | 34 | ||||
| -rw-r--r-- | src-migrate/modules/register/components/RegistrasiBisnis.tsx | 4 | ||||
| -rw-r--r-- | src-migrate/modules/register/index.tsx | 7 | ||||
| -rw-r--r-- | src-migrate/modules/register/stores/usePengajuanTempoStore.ts | 14 | ||||
| -rw-r--r-- | src-migrate/modules/side-banner/index.tsx | 11 | ||||
| -rw-r--r-- | src-migrate/pages/api/product-variant/[id].tsx | 4 | ||||
| -rw-r--r-- | src-migrate/services/banner.ts | 9 | ||||
| -rw-r--r-- | src-migrate/types/auth.ts | 2 | ||||
| -rw-r--r-- | src-migrate/types/tempo.ts | 5 | ||||
| -rw-r--r-- | src-migrate/validations/tempo.ts | 110 |
13 files changed, 192 insertions, 67 deletions
diff --git a/src-migrate/modules/cart/components/Item.tsx b/src-migrate/modules/cart/components/Item.tsx index ab2e7ce1..86d1dc43 100644 --- a/src-migrate/modules/cart/components/Item.tsx +++ b/src-migrate/modules/cart/components/Item.tsx @@ -1,5 +1,6 @@ import style from '../styles/item.module.css' - +import odooApi from '~/libs/odooApi'; +import { useEffect, useState } from 'react'; import { Skeleton, SkeletonProps, Tooltip } from '@chakra-ui/react' import { InfoIcon } from 'lucide-react' import Image from 'next/image' @@ -22,6 +23,17 @@ type Props = { } const CartItem = ({ item, editable = true, selfPicking}: Props) => { + const [qtyPickUp, setQtyPickUp] = useState(0); + useEffect(() => { + const fetchData = async () => { + const qty_available = await odooApi( + 'GET', + `/api/v1/product_variant/${item.id}/qty_available` + ); + setQtyPickUp(qty_available?.qty); + }; + fetchData(); + }, [item]); return ( <div className={style.wrapper}> {item.cart_type === 'promotion' && ( @@ -54,11 +66,11 @@ const CartItem = ({ item, editable = true, selfPicking}: Props) => { <CartItem.Image item={item} /> <div className={style.details}> - {item?.available_quantity > 0 && ( + {qtyPickUp > 0 && ( <div className='text-[10px] text-red-500 italic'> - {item.quantity <= item?.available_quantity + {item.quantity <= qtyPickUp ? '*Barang ini bisa di pickup maksimal pukul 16.00' - : `*${item?.available_quantity} Barang ini bisa di pickup maksimal pukul 16.00`} + : `*${qtyPickUp} Barang ini bisa di pickup maksimal pukul 16.00`} </div> )} <CartItem.Name item={item} /> diff --git a/src-migrate/modules/product-detail/components/AddToCart.tsx b/src-migrate/modules/product-detail/components/AddToCart.tsx index 280e4a7a..95bc1d88 100644 --- a/src-migrate/modules/product-detail/components/AddToCart.tsx +++ b/src-migrate/modules/product-detail/components/AddToCart.tsx @@ -15,7 +15,8 @@ import { useProductCartContext } from '@/contexts/ProductCartContext'; import { createSlug } from '~/libs/slug'; import formatCurrency from '~/libs/formatCurrency'; import { useProductDetail } from '../stores/useProductDetail'; - +import { gtagAddToCart } from '@/core/utils/googleTag'; +import axios from 'axios'; type Props = { variantId: number | null; quantity?: number; @@ -50,6 +51,38 @@ const AddToCart = ({ isLoading, setIsloading, } = useProductCartContext(); + const [activeVariant, setActiveVariant] = useState({ + id: 0, + code: '', + name: '', + price: '', + stock: '', + weight: '', + isFlashSale: false, + }); + + useEffect(() => { + const fetchData = async () => { + if (variantId) { + let response = await axios( + `${process.env.NEXT_PUBLIC_SELF_HOST}/api/shop/variant-detail?id=${variantId}` + ); + let productVariant = response.data; + if (productVariant) { + setActiveVariant({ + id: productVariant[0].id, + code: productVariant[0].code, + name: productVariant[0].name, + price: productVariant[0].price.price, + stock: productVariant[0].stockTotal, + weight: productVariant[0].weight, + isFlashSale: productVariant[0].isFlashsale, + }); + } + } + }; + fetchData(); + }, [variantId]); const productSimilarQuery = [ product?.name, @@ -101,6 +134,8 @@ const AddToCart = ({ setRefreshCart(true); setAddCartAlert(true); + gtagAddToCart(activeVariant, quantity); + toast({ title: 'Tambah ke keranjang', description: 'Berhasil menambahkan barang ke keranjang belanja', diff --git a/src-migrate/modules/product-detail/components/PriceAction.tsx b/src-migrate/modules/product-detail/components/PriceAction.tsx index 9348bbfb..850c2d9d 100644 --- a/src-migrate/modules/product-detail/components/PriceAction.tsx +++ b/src-migrate/modules/product-detail/components/PriceAction.tsx @@ -163,7 +163,7 @@ const PriceAction = ({ product }: Props) => { </span> */} </div> <div> - {selectedVariant?.is_in_bu && ( + {qtyPickUp > 0 && ( <Link href='/panduan-pick-up-service' className='group'> <Image src='/images/PICKUP-NOW.png' diff --git a/src-migrate/modules/product-detail/components/ProductDetail.tsx b/src-migrate/modules/product-detail/components/ProductDetail.tsx index b036cc2d..4667e086 100644 --- a/src-migrate/modules/product-detail/components/ProductDetail.tsx +++ b/src-migrate/modules/product-detail/components/ProductDetail.tsx @@ -66,7 +66,11 @@ const ProductDetail = ({ product }: Props) => { if (typeof auth === 'object') { setIsApproval(auth?.feature?.soApproval); } - setSelectedVariant(product?.variants[0]) + const selectedVariant = + product?.variants?.find((variant) => variant.is_in_bu) || + product?.variants?.[0]; + setSelectedVariant(selectedVariant); + // setSelectedVariant(product?.variants[0]) }, []); return ( @@ -102,7 +106,12 @@ const ProductDetail = ({ product }: Props) => { )} <div className='h-4 md:h-10' /> - {!!activeVariantId && !isApproval && <ProductPromoSection product={product} productId={activeVariantId} />} + {!!activeVariantId && !isApproval && ( + <ProductPromoSection + product={product} + productId={activeVariantId} + /> + )} {/* <div className={style['section-card']}> <h2 className={style['heading']}> @@ -117,15 +126,18 @@ const ProductDetail = ({ product }: Props) => { <div className={style['section-card']}> <h2 className={style['heading']}>Informasi Produk</h2> <div className='h-4' /> - <div - className={style['description']} - dangerouslySetInnerHTML={{ - __html: - !product.description || product.description == '<p><br></p>' - ? 'Belum ada deskripsi' - : product.description, - }} - /> + <div className='overflow-x-auto'> + <div + className={style['description']} + dangerouslySetInnerHTML={{ + __html: + !product.description || + product.description == '<p><br></p>' + ? 'Belum ada deskripsi' + : product.description, + }} + /> + </div> </div> </div> </div> diff --git a/src-migrate/modules/register/components/RegistrasiBisnis.tsx b/src-migrate/modules/register/components/RegistrasiBisnis.tsx index 332c5358..5933b5f2 100644 --- a/src-migrate/modules/register/components/RegistrasiBisnis.tsx +++ b/src-migrate/modules/register/components/RegistrasiBisnis.tsx @@ -13,11 +13,11 @@ const RegistrasiBisnis: React.FC<FormProps> = ({ chekValid, buttonSubmitClick, }) => { - const [isPKP, setIsPKP] = useState(true); + const [isPKP, setIsPKP] = useState(false); const [isTerdaftar, setIsTerdaftar] = useState(false); const [isDropIndividu, setIsDropIndividu] = useState(true); const [isBisnisClicked, setisBisnisClicked] = useState(true); - const [selectedValue, setSelectedValue] = useState('PKP'); + const [selectedValue, setSelectedValue] = useState('Non-PKP'); const [selectedValueBisnis, setSelectedValueBisnis] = useState('false'); const { validate, updateForm } = useRegisterStore(); diff --git a/src-migrate/modules/register/index.tsx b/src-migrate/modules/register/index.tsx index 39f4771c..06f7cbea 100644 --- a/src-migrate/modules/register/index.tsx +++ b/src-migrate/modules/register/index.tsx @@ -101,6 +101,13 @@ const Register = () => { status: 'warning', }); break; + case 'BISNIS_NOT_FOUND': + toast({ + ...toastProps, + title: 'Bisnis tidak ditemukan', + status: 'warning', + }); + break; } }; diff --git a/src-migrate/modules/register/stores/usePengajuanTempoStore.ts b/src-migrate/modules/register/stores/usePengajuanTempoStore.ts index 1e086c06..79ab3612 100644 --- a/src-migrate/modules/register/stores/usePengajuanTempoStore.ts +++ b/src-migrate/modules/register/stores/usePengajuanTempoStore.ts @@ -171,7 +171,7 @@ type StatePengiriman = { }; type ActionPengiriman = { updateFormPengiriman: (name: string, value: string) => void; - + updateDokumenProsedur: (name: string, format: string, base64: string) => void; validatePengiriman: () => void; }; export const usePengajuanTempoStorePengiriman = create< @@ -186,6 +186,8 @@ export const usePengajuanTempoStorePengiriman = create< districtPengiriman: '', subDistrictPengiriman: '', zipPengiriman: '', + PICBarangMobile: '', + invoicePicMobile: '', invoicePicTittle: '', invoicePic: '', isSameAddrees: '', @@ -202,12 +204,21 @@ export const usePengajuanTempoStorePengiriman = create< dokumenPengirimanInput: '', dokumenKirimInput: '', dokumenPengirimanInvoice: '', + dokumenProsedur: { name: '', format: '', base64: '' }, }, updateFormPengiriman: (name, value) => set((state) => ({ formPengiriman: { ...state.formPengiriman, [name]: value }, })), + updateDokumenProsedur: (name, format, base64) => + set((state) => ({ + formPengiriman: { + ...state.formPengiriman, + dokumenProsedur: { name, format, base64 }, + }, + })), + errorsPengiriman: {}, validatePengiriman: () => { try { @@ -260,6 +271,7 @@ export const usePengajuanTempoStoreDokumen = create< dokumenLaporanKeuangan: { name: '', format: '', base64: '' }, dokumenFotoKantor: { name: '', format: '', base64: '' }, dokumenTempatBekerja: { name: '', format: '', base64: '' }, + dokumenProsedur: { name: '', format: '', base64: '' }, }, // Memperbarui dokumen dengan name, format, dan base64 diff --git a/src-migrate/modules/side-banner/index.tsx b/src-migrate/modules/side-banner/index.tsx index 878b8e70..7bc5f394 100644 --- a/src-migrate/modules/side-banner/index.tsx +++ b/src-migrate/modules/side-banner/index.tsx @@ -5,12 +5,15 @@ import Image from "~/components/ui/image";; import { getBanner } from "~/services/banner"; import { getRandomInt } from '@/utils/getRandomInt'; -const SideBanner = () => { +interface SideBannerProps { + query?: string; // Menentukan bahwa 'query' adalah string (bisa undefined) +} + +const SideBanner: React.FC<SideBannerProps> = ({ query }) => { const fetchSideBanner = useQuery({ - queryKey: 'sideBanner', - queryFn: () => getBanner({ type: 'side-banner-search' }) + queryKey: ["sideBanner", query], + queryFn: () => getBanner({ type: "side-banner-search", keyword: query }), }); - const length = useMemo(() => fetchSideBanner.data?.length, [fetchSideBanner.data]); const randomIndex = useMemo(() => getRandomInt(length), [length]); const banner = fetchSideBanner?.data?.[randomIndex] || false; diff --git a/src-migrate/pages/api/product-variant/[id].tsx b/src-migrate/pages/api/product-variant/[id].tsx index 2c46ac89..0f7524d0 100644 --- a/src-migrate/pages/api/product-variant/[id].tsx +++ b/src-migrate/pages/api/product-variant/[id].tsx @@ -6,7 +6,7 @@ const SOLR_HOST = process.env.SOLR_HOST as string export default async function handler(req: NextApiRequest, res: NextApiResponse) { const variantId = req.query.id as string - let price_tier = 'tier1' + let price_tier = 'tier1_v2' let auth = req.cookies.auth ? JSON.parse(req.cookies.auth) : null if (auth?.pricelist) price_tier = auth.pricelist @@ -29,7 +29,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const map = async (variant: any, price_tier: string) => { const data: any = {} - const price = variant[`price_${price_tier}_v2_f`] || 0 + const price = variant[`price_${price_tier}_f`] || 0 data.id = parseInt(variant.id) data.parent_id = variant.template_id_i diff --git a/src-migrate/services/banner.ts b/src-migrate/services/banner.ts index 1b46ba06..7fb922cf 100644 --- a/src-migrate/services/banner.ts +++ b/src-migrate/services/banner.ts @@ -3,9 +3,16 @@ import { IBanner } from '~/types/banner'; export const getBanner = async ({ type, + keyword, }: { type: string; + keyword?: string; // Tambahkan keyword sebagai parameter opsional }): Promise<IBanner[]> => { const searchParams = new URLSearchParams({ type }); - return await odooApi('GET', `/api/v1/banner?${searchParams.toString()}`); + + if (keyword) { + searchParams.append("keyword", keyword); + } + + return await odooApi("GET", `/api/v1/banner?${searchParams.toString()}`); }; diff --git a/src-migrate/types/auth.ts b/src-migrate/types/auth.ts index 1b400e95..f451ef75 100644 --- a/src-migrate/types/auth.ts +++ b/src-migrate/types/auth.ts @@ -30,7 +30,7 @@ export type RegisterProps = z.infer<typeof registerSchema>; export type RegisterResApiProps = { register: boolean; - reason: 'EMAIL_USED' | 'NOT_ACTIVE' | null; + reason: 'EMAIL_USED' | 'NOT_ACTIVE' | 'BISNIS_NOT_FOUND' | null; }; type ActivationResProps = { diff --git a/src-migrate/types/tempo.ts b/src-migrate/types/tempo.ts index d043e2d6..880a30bb 100644 --- a/src-migrate/types/tempo.ts +++ b/src-migrate/types/tempo.ts @@ -42,6 +42,8 @@ export type tempoPropsPengiriman = { cityPengiriman: string; streetInvoice: string; zip: string; + PICBarangMobile: string; + invoicePicMobile: string; invoicePic: string; isSameAddrees: string; stateInvoice: string; @@ -52,6 +54,7 @@ export type tempoPropsPengiriman = { dokumenPengirimanInput: string; dokumenPengirimanInvoice: string; dokumenPengirimanInvoiceInput: string; + dokumenProsedur: string; }; export type tempoPropsSupplier = { supplier: string; @@ -82,7 +85,7 @@ export type TempoPropsDokumen = z.infer<typeof TempoSchemaDokumen>; export type TempoResApiProps = { Tempo: boolean; - reason: 'EMAIL_USED' | 'NOT_ACTIVE' | null; + reason: 'EMAIL_USED' | 'NOT_ACTIVE' | 'BISNIS_NOT_FOUND' | null; }; type ActivationResProps = { diff --git a/src-migrate/validations/tempo.ts b/src-migrate/validations/tempo.ts index f019275c..cf5914b5 100644 --- a/src-migrate/validations/tempo.ts +++ b/src-migrate/validations/tempo.ts @@ -8,7 +8,7 @@ export const TempoSchema = z.object({ state: z.string().min(1, { message: 'Provinsi harus dipilih' }), city: z.string().min(1, { message: 'Kota harus dipilih' }), district: z.string().min(1, { message: 'Kecamatan harus dipilih' }), - subDistrict: z.string().min(1, { message: 'Kelurahan harus dipilih' }), + subDistrict: z.string().optional(), mobile: z .string() .min(1, { message: 'Nomor telepon harus diisi' }) @@ -33,50 +33,81 @@ export const TempoSchema = z.object({ .min(1, { message: 'Category produk harus dipilih' }), }); -export const TempoSchemaKontakPerson = z.object({ - direkturName: z.string().min(1, { message: 'Nama harus diisi' }), - direkturTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), - financeName: z.string().min(1, { message: 'Nama harus diisi' }), - direkturMobile: z.string().optional(), - financeMobile: z +export const TempoSchemaKontakPerson = z + .object({ + direkturName: z.string().min(1, { message: 'Nama harus diisi' }), + direkturTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), + financeName: z.string().min(1, { message: 'Nama harus diisi' }), + direkturMobile: z.string().optional(), + financeMobile: z + .string() + .min(1, { message: 'Nomor telepon harus diisi' }) + .refine((val) => /^\d{10,12}$/.test(val), { + message: 'Format nomor telepon tidak valid, contoh: 081234567890', + }), + purchasingTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), + financeTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), + purchasingMobile: z + .string() + .min(1, { message: 'Nomor telepon harus diisi' }) + .refine((val) => /^\d{10,12}$/.test(val), { + message: 'Format nomor telepon tidak valid, contoh: 081234567890', + }), + direkturEmail: z + .string() + .min(1, { message: 'Email harus diisi' }) + .email({ message: 'Email harus menggunakan format example@mail.com' }), + purchasingEmail: z + .string() + .min(1, { message: 'Email harus diisi' }) + .email({ message: 'Email harus menggunakan format example@mail.com' }), + financeEmail: z + .string() + .min(1, { message: 'Email harus diisi' }) + .email({ message: 'Email harus menggunakan format example@mail.com' }), + purchasingName: z.string().min(1, { message: 'Nama harus diisi' }), + }) + .refine( + (data) => + !data.financeEmail || // Jika financeEmail kosong, tidak perlu validasi + data.financeEmail !== data.purchasingEmail, // Validasi jika financeEmail ada + { + message: 'Email Finance tidak boleh sama dengan Email Purchasing', + path: ['financeEmail'], + } + ) + .refine( + (data) => + !data.direkturEmail || + (data.direkturEmail !== data.financeEmail && + data.direkturEmail !== data.purchasingEmail), + { + message: + 'Email Direktur tidak boleh sama dengan Email Finance atau Purchasing', + path: ['direkturEmail'], + } + ); +export const TempoSchemaPengiriman = z.object({ + PICTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), + PICName: z.string().min(1, { message: 'Nama harus diisi' }), + streetPengiriman: z.string().min(1, { message: 'Alamat harus diisi' }), + statePengiriman: z.string().min(1, { message: 'Provinsi harus dipilih' }), + cityPengiriman: z.string().min(1, { message: 'Kota harus dipilih' }), + districtPengiriman: z.string().min(1, { message: 'Kecamatan harus dipilih' }), + subDistrictPengiriman: z.string().optional(), + zipPengiriman: z.string().min(1, { message: 'Kode pos harus diisi' }), + PICBarangMobile: z .string() .min(1, { message: 'Nomor telepon harus diisi' }) .refine((val) => /^\d{10,12}$/.test(val), { message: 'Format nomor telepon tidak valid, contoh: 081234567890', }), - purchasingTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), - financeTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), - purchasingMobile: z + invoicePicMobile: z .string() .min(1, { message: 'Nomor telepon harus diisi' }) .refine((val) => /^\d{10,12}$/.test(val), { message: 'Format nomor telepon tidak valid, contoh: 081234567890', }), - direkturEmail: z - .string() - .min(1, { message: 'Email harus diisi' }) - .email({ message: 'Email harus menggunakan format example@mail.com' }), - purchasingEmail: z - .string() - .min(1, { message: 'Email harus diisi' }) - .email({ message: 'Email harus menggunakan format example@mail.com' }), - financeEmail: z - .string() - .min(1, { message: 'Email harus diisi' }) - .email({ message: 'Email harus menggunakan format example@mail.com' }), - purchasingName: z.string().min(1, { message: 'Nama harus diisi' }), -}); -export const TempoSchemaPengiriman = z.object({ - PICTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), - PICName: z.string().min(1, { message: 'Nama harus diisi' }), - streetPengiriman: z.string().min(1, { message: 'Alamat harus diisi' }), - statePengiriman: z.string().min(1, { message: 'Provinsi harus dipilih' }), - cityPengiriman: z.string().min(1, { message: 'Kota harus dipilih' }), - districtPengiriman: z.string().min(1, { message: 'Kecamatan harus dipilih' }), - subDistrictPengiriman: z - .string() - .min(1, { message: 'Kelurahan harus dipilih' }), - zipPengiriman: z.string().min(1, { message: 'Kode pos harus diisi' }), invoicePicTittle: z.string().min(1, { message: 'Tittle harus dipilih' }), invoicePic: z.string().min(1, { message: 'Nama pic invoice harus diisi' }), streetInvoice: z.string().min(1, { message: 'Alamat invoice harus diisi' }), @@ -87,9 +118,7 @@ export const TempoSchemaPengiriman = z.object({ districtInvoice: z .string() .min(1, { message: 'Kecamatan invoice harus dipilih' }), - subDistrictInvoice: z - .string() - .min(1, { message: 'Kelurahan invoice harus dipilih' }), + subDistrictInvoice: z.string().optional(), zipInvoice: z.string().min(1, { message: 'Kode pos harus diisi' }), isSameAddrees: z.string(), isSameAddreesStreet: z.string(), @@ -99,6 +128,11 @@ export const TempoSchemaPengiriman = z.object({ dokumenPengirimanInput: z.string().optional(), dokumenKirimInput: z.string().optional(), dokumenPengirimanInvoiceInput: z.string().optional(), + dokumenProsedur: z.object({ + name: z.string().optional(), + format: z.string().optional(), + base64: z.string().optional(), + }), }); export const TempoSchemaSupplier = z.object({ supplier: z.string().min(1, { message: 'Nama supplier harus diisi' }), |
