diff options
| -rw-r--r-- | src/core/components/elements/Footer/BasicFooter.jsx | 4 | ||||
| -rw-r--r-- | src/core/components/elements/Footer/SimpleFooter.jsx | 22 | ||||
| -rw-r--r-- | src/core/components/elements/Link/Link.jsx | 1 | ||||
| -rw-r--r-- | src/core/components/elements/Navbar/NavbarDesktop.jsx | 13 | ||||
| -rw-r--r-- | src/core/components/elements/Sidebar/Sidebar.jsx | 31 | ||||
| -rw-r--r-- | src/images/logo.png | bin | 49879 -> 47325 bytes | |||
| -rw-r--r-- | src/lib/auth/components/IsAuth.jsx | 4 | ||||
| -rw-r--r-- | src/lib/auth/hooks/useLogin.js | 2 | ||||
| -rw-r--r-- | src/lib/blog/api/blogApi.js | 8 | ||||
| -rw-r--r-- | src/lib/blog/api/blogsApi.js | 8 | ||||
| -rw-r--r-- | src/lib/blog/hooks/useBlog.js | 11 | ||||
| -rw-r--r-- | src/lib/blog/hooks/useBlogs.js | 13 | ||||
| -rw-r--r-- | src/lib/brand/components/Brand.jsx | 2 | ||||
| -rw-r--r-- | src/lib/checkout/email/FinishCheckoutEmail.jsx | 15 | ||||
| -rw-r--r-- | src/lib/home/components/HeroBanner.jsx | 54 | ||||
| -rw-r--r-- | src/lib/product/components/Product/ProductDesktop.jsx | 22 | ||||
| -rw-r--r-- | src/pages/about-us.jsx | 4 | ||||
| -rw-r--r-- | src/pages/blog/[slug].jsx | 54 | ||||
| -rw-r--r-- | src/pages/blog/index.jsx | 90 | ||||
| -rw-r--r-- | src/pages/video.jsx | 2 |
20 files changed, 230 insertions, 130 deletions
diff --git a/src/core/components/elements/Footer/BasicFooter.jsx b/src/core/components/elements/Footer/BasicFooter.jsx index 25f8f552..79b78dee 100644 --- a/src/core/components/elements/Footer/BasicFooter.jsx +++ b/src/core/components/elements/Footer/BasicFooter.jsx @@ -178,7 +178,9 @@ const InformationCenter = () => ( </li> <li className='text-gray_r-12/80 flex items-center'> <DevicePhoneMobileIcon className='w-[18px] mr-2' /> - <a href='https://wa.me/+628128080622'>0812-8080-622</a> + <a href='https://wa.me/628128080622' target='_blank' rel='noreferrer'> + 0812-8080-622 + </a> </li> </ul> </div> diff --git a/src/core/components/elements/Footer/SimpleFooter.jsx b/src/core/components/elements/Footer/SimpleFooter.jsx index 0fbc8f62..41ca6094 100644 --- a/src/core/components/elements/Footer/SimpleFooter.jsx +++ b/src/core/components/elements/Footer/SimpleFooter.jsx @@ -20,22 +20,24 @@ const SimpleFooter = () => ( </li> <li className='text-gray_r-12/80 flex items-center'> <DevicePhoneMobileIcon className='w-[18px] mr-2' /> - <a href='https://wa.me/+628128080622'>0812-8080-622</a> + <a href='https://wa.me/628128080622' target='_blank' rel='noreferrer'> + 0812-8080-622 + </a> </li> </ul> </div> <div className='w-1/2 pl-2'> <div className='font-semibold mb-3'>Jam Operasional</div> <ul className='flex flex-col gap-y-1'> - <li> - <div className='text-gray_r-12 mb-0.5'>Senin - Jumat:</div> - <div className='text-gray_r-12/80'>08:30 - 17:00</div> - </li> - <li> - <div className='text-gray_r-12 mb-0.5'>Sabtu:</div> - <div className='text-gray_r-12/80'>08:30 - 14:00</div> - </li> - </ul> + <li> + <div className='text-gray_r-12 mb-0.5'>Senin - Jumat:</div> + <div className='text-gray_r-12/80'>08:30 - 17:00</div> + </li> + <li> + <div className='text-gray_r-12 mb-0.5'>Sabtu:</div> + <div className='text-gray_r-12/80'>08:30 - 14:00</div> + </li> + </ul> </div> </footer> ) diff --git a/src/core/components/elements/Link/Link.jsx b/src/core/components/elements/Link/Link.jsx index dbc65338..75fc6ca8 100644 --- a/src/core/components/elements/Link/Link.jsx +++ b/src/core/components/elements/Link/Link.jsx @@ -4,6 +4,7 @@ const Link = ({ children, ...props }) => { return ( <NextLink {...props} + onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })} scroll={false} className={`block font-medium text-red_r-11 ${props?.className || ''}`} > diff --git a/src/core/components/elements/Navbar/NavbarDesktop.jsx b/src/core/components/elements/Navbar/NavbarDesktop.jsx index 5d7fe846..306b6e83 100644 --- a/src/core/components/elements/Navbar/NavbarDesktop.jsx +++ b/src/core/components/elements/Navbar/NavbarDesktop.jsx @@ -44,9 +44,11 @@ const NavbarDesktop = () => { <nav className='py-6 sticky top-0 z-50 bg-white border-b border-gray_r-6'> <div className='container mx-auto flex gap-x-6'> <Link href='/'> - <Image src={IndoteknikLogo} alt='Indoteknik Logo' width={180} height={60} /> + <Image src={IndoteknikLogo} alt='Indoteknik Logo' width={210} height={210 / 3} /> </Link> - <Search /> + <div className='flex-1 flex items-center'> + <Search /> + </div> <div className='flex gap-x-4'> <Link href='/my/transactions' className='flex items-center gap-x-2 !text-gray_r-12/80'> <DocumentCheckIcon className='w-7' /> @@ -64,7 +66,12 @@ const NavbarDesktop = () => { <HeartIcon className='w-7' /> Wishlist </Link> - <a href='https://wa.me/628' className='flex items-center gap-x-1 !text-gray_r-12/80'> + <a + href='https://wa.me/628128080622' + target='_blank' + rel='noreferrer' + className='flex items-center gap-x-1 !text-gray_r-12/80' + > <Image src='/images/socials/Whatsapp-2.png' alt='Whatsapp' width={48} height={48} /> <div> <div className='font-semibold'>Whatsapp</div> diff --git a/src/core/components/elements/Sidebar/Sidebar.jsx b/src/core/components/elements/Sidebar/Sidebar.jsx index 18ed6ac1..c8fd8bab 100644 --- a/src/core/components/elements/Sidebar/Sidebar.jsx +++ b/src/core/components/elements/Sidebar/Sidebar.jsx @@ -10,10 +10,7 @@ const Sidebar = ({ active, close }) => { const auth = useAuth() const SidebarLink = ({ children, ...props }) => ( - <Link - {...props} - onClick={close} - > + <Link {...props} onClick={close}> {children} </Link> ) @@ -120,28 +117,22 @@ const Sidebar = ({ active, close }) => { </> )} </div> - <SidebarLink - className={itemClassName} - href='/shop/brands' - > + <SidebarLink className={itemClassName} href='/shop/brands'> Semua Brand </SidebarLink> - <SidebarLink - className={itemClassName} - href='/about-us' - > + <SidebarLink className={itemClassName} href='/blog'> + Blog Indoteknik + </SidebarLink> + <SidebarLink className={itemClassName} href='/video'> + Indoteknik TV + </SidebarLink> + <SidebarLink className={itemClassName} href='/about-us'> Tentang Indoteknik </SidebarLink> - <SidebarLink - className={itemClassName} - href='/faqs' - > + <SidebarLink className={itemClassName} href='/faqs'> F.A.Q </SidebarLink> - <SidebarLink - className={itemClassName} - href='/contact-us' - > + <SidebarLink className={itemClassName} href='/contact-us'> Hubungi Kami </SidebarLink> <button diff --git a/src/images/logo.png b/src/images/logo.png Binary files differindex 87c696aa..dccc0cd6 100644 --- a/src/images/logo.png +++ b/src/images/logo.png diff --git a/src/lib/auth/components/IsAuth.jsx b/src/lib/auth/components/IsAuth.jsx index 1cfd3172..a32e648c 100644 --- a/src/lib/auth/components/IsAuth.jsx +++ b/src/lib/auth/components/IsAuth.jsx @@ -7,8 +7,8 @@ const IsAuth = ({ children }) => { const [response, setResponse] = useState(<></>) useEffect(() => { - if (!getAuth()) { - router.replace('/login') + if (!getAuth() && router.pathname != '/login') { + router.replace(`/login?next=${router.asPath}`) } else { setResponse(children) } diff --git a/src/lib/auth/hooks/useLogin.js b/src/lib/auth/hooks/useLogin.js index bef36053..1d5ff43d 100644 --- a/src/lib/auth/hooks/useLogin.js +++ b/src/lib/auth/hooks/useLogin.js @@ -34,7 +34,7 @@ const useLogin = () => { if (login.isAuth) { setAuth(login.user) - router.push('/') + router.push(router.query?.next || '/') return } switch (login.reason) { diff --git a/src/lib/blog/api/blogApi.js b/src/lib/blog/api/blogApi.js new file mode 100644 index 00000000..e38c9cd5 --- /dev/null +++ b/src/lib/blog/api/blogApi.js @@ -0,0 +1,8 @@ +import odooApi from '@/core/api/odooApi' + +const blogApi = async ({ id }) => { + const dataBlog = await odooApi('GET', `/api/v1/blog/${id}`) + return dataBlog +} + +export default blogApi diff --git a/src/lib/blog/api/blogsApi.js b/src/lib/blog/api/blogsApi.js new file mode 100644 index 00000000..8943c61e --- /dev/null +++ b/src/lib/blog/api/blogsApi.js @@ -0,0 +1,8 @@ +import odooApi from '@/core/api/odooApi' + +const blogsApi = async ({ limit, offset }) => { + const dataBlogs = await odooApi('GET', `/api/v1/blog?limit=${limit}&offset=${offset}`) + return dataBlogs +} + +export default blogsApi diff --git a/src/lib/blog/hooks/useBlog.js b/src/lib/blog/hooks/useBlog.js new file mode 100644 index 00000000..bc01be7f --- /dev/null +++ b/src/lib/blog/hooks/useBlog.js @@ -0,0 +1,11 @@ +import { useQuery } from 'react-query' +import blogApi from '../api/blogApi' + +const useBlog = ({ id }) => { + const fetchBlog = async () => await blogApi({ id }) + const blog = useQuery(`blog-${id}`, fetchBlog) + + return { blog } +} + +export default useBlog diff --git a/src/lib/blog/hooks/useBlogs.js b/src/lib/blog/hooks/useBlogs.js new file mode 100644 index 00000000..edcea020 --- /dev/null +++ b/src/lib/blog/hooks/useBlogs.js @@ -0,0 +1,13 @@ +import { useQuery } from 'react-query' +import blogsApi from '../api/blogsApi' + +const useBlogs = ({ limit, offset }) => { + const fetchBlogs = async () => await blogsApi({ limit, offset }) + const blogs = useQuery(`blogs-${limit}-${offset}`, fetchBlogs, { + refetchOnWindowFocus: false + }) + + return { blogs } +} + +export default useBlogs diff --git a/src/lib/brand/components/Brand.jsx b/src/lib/brand/components/Brand.jsx index db4e81da..6e156b8e 100644 --- a/src/lib/brand/components/Brand.jsx +++ b/src/lib/brand/components/Brand.jsx @@ -27,7 +27,7 @@ const Brand = ({ id }) => { <> <MobileView> <> - <div className='min-h-[150px]'> + <div> {brand.isLoading && <ImageSkeleton />} {brand.data && ( <> diff --git a/src/lib/checkout/email/FinishCheckoutEmail.jsx b/src/lib/checkout/email/FinishCheckoutEmail.jsx index 2c31b815..e8f63afa 100644 --- a/src/lib/checkout/email/FinishCheckoutEmail.jsx +++ b/src/lib/checkout/email/FinishCheckoutEmail.jsx @@ -160,15 +160,9 @@ const FinishCheckoutEmail = ({ transaction, payment, statusPayment }) => { <Hr style={style.hr} /> {transaction.products.map((product) => ( - <Row - style={style.productRow} - key={product.id} - > + <Row style={style.productRow} key={product.id}> <Column style={style.productLCol}> - <Img - src={product.parent.image} - width='100%' - /> + <Img src={product.parent.image} width='100%' /> </Column> <Column style={style.productRCol}> <Text style={style.productName}>{product.name}</Text> @@ -261,7 +255,10 @@ const FinishCheckoutEmail = ({ transaction, payment, statusPayment }) => { Jika ada pertanyaan seputar teknis pembayaran {transaction.address.customer.name}{' '} dapat hubungi kami melalui Email{' '} <a href='mailto:sales@indoteknik.com'>(sales@indoteknik.com)</a> atau Whatsapp{' '} - <a href='https://wa.me/628128080622'>(+62 812-8080-622)</a>. + <a href='https://wa.me/628128080622' target='_blank' rel='noreferrer'> + (+62 812-8080-622) + </a> + . </Text> <Text style={style.text}> Terima kasih atas perhatiannya, selamat kembali beraktifitas diff --git a/src/lib/home/components/HeroBanner.jsx b/src/lib/home/components/HeroBanner.jsx index 95f590fc..e6136e03 100644 --- a/src/lib/home/components/HeroBanner.jsx +++ b/src/lib/home/components/HeroBanner.jsx @@ -8,14 +8,23 @@ import { Pagination, Autoplay } from 'swiper' import 'swiper/css' import 'swiper/css/pagination' import 'swiper/css/autoplay' -import useDevice from '@/core/hooks/useDevice' +import MobileView from '@/core/components/views/MobileView' +import DesktopView from '@/core/components/views/DesktopView' const HeroBanner = () => { - const { isMobile } = useDevice() const { heroBanners } = useHeroBanner() - const swiperBanner = { - pagination: { dynamicBullets: isMobile ? true : false, clickable: true }, + const swiperBannerMobile = { + pagination: { dynamicBullets: true, clickable: true }, + autoplay: { + delay: 6000, + disableOnInteraction: false + }, + modules: [Pagination, Autoplay] + } + + const swiperBannerDesktop = { + pagination: { dynamicBullets: false, clickable: true }, autoplay: { delay: 6000, disableOnInteraction: false @@ -27,23 +36,26 @@ const HeroBanner = () => { <div className='min-h-[200px]'> {heroBanners.isLoading && <ImageSkeleton />} {!heroBanners.isLoading && ( - <Swiper - slidesPerView={1} - pagination={swiperBanner.pagination} - modules={swiperBanner.modules} - autoplay={swiperBanner.autoplay} - className='border border-gray_r-6' - > - {heroBanners.data?.map((banner, index) => ( - <SwiperSlide key={index}> - <Image - src={banner.image} - alt={banner.name} - className='w-full h-auto' - /> - </SwiperSlide> - ))} - </Swiper> + <> + <MobileView> + <Swiper slidesPerView={1} className='border border-gray_r-6' {...swiperBannerMobile}> + {heroBanners.data?.map((banner, index) => ( + <SwiperSlide key={index}> + <Image src={banner.image} alt={banner.name} className='w-full h-auto' /> + </SwiperSlide> + ))} + </Swiper> + </MobileView> + <DesktopView> + <Swiper slidesPerView={1} className='border border-gray_r-6' {...swiperBannerDesktop}> + {heroBanners.data?.map((banner, index) => ( + <SwiperSlide key={index}> + <Image src={banner.image} alt={banner.name} className='w-full h-auto' /> + </SwiperSlide> + ))} + </Swiper> + </DesktopView> + </> )} </div> ) diff --git a/src/lib/product/components/Product/ProductDesktop.jsx b/src/lib/product/components/Product/ProductDesktop.jsx index 2f0ac488..0866bffa 100644 --- a/src/lib/product/components/Product/ProductDesktop.jsx +++ b/src/lib/product/components/Product/ProductDesktop.jsx @@ -276,20 +276,22 @@ const VariantPrice = ({ id }) => { return ( <> - {variantPrice?.data?.discount > 0 && ( + {variantPrice?.data?.discount > 0 && variantPrice?.data?.priceExcludeAfterDiscount > 0 && ( <> - <span className='line-through text-caption-1 text-gray_r-11'> + <div className='line-through text-caption-1 text-gray_r-11 mb-1'> {currencyFormat(variantPrice?.data?.priceExclude)} - </span>{' '} + </div>{' '} </> )} - {variantPrice?.data?.priceExcludeAfterDiscount > 0 ? ( - currencyFormat(variantPrice?.data?.priceExcludeAfterDiscount) - ) : ( - <a href='https://wa.me/' className='text-red_r-11'> - Call for price - </a> - )} + <div> + {variantPrice?.data?.priceExcludeAfterDiscount > 0 ? ( + currencyFormat(variantPrice?.data?.priceExcludeAfterDiscount) + ) : ( + <a href='https://wa.me/' className='text-red_r-11'> + Call for price + </a> + )} + </div> </> ) } diff --git a/src/pages/about-us.jsx b/src/pages/about-us.jsx index 9bc67673..9c9c8baf 100644 --- a/src/pages/about-us.jsx +++ b/src/pages/about-us.jsx @@ -4,7 +4,9 @@ import PageContent from '@/lib/content/components/PageContent' export default function AboutUs() { return ( <BasicLayout> - <PageContent path='/about-us' /> + <div className='container mx-auto p-4 md:p-0 my-0 md:my-10'> + <PageContent path='/about-us' /> + </div> </BasicLayout> ) } diff --git a/src/pages/blog/[slug].jsx b/src/pages/blog/[slug].jsx index e69de29b..63e53bf0 100644 --- a/src/pages/blog/[slug].jsx +++ b/src/pages/blog/[slug].jsx @@ -0,0 +1,54 @@ +import Link from '@/core/components/elements/Link/Link' +import BasicLayout from '@/core/components/layouts/BasicLayout' +import { createSlug, getIdFromSlug } from '@/core/utils/slug' +import useBlog from '@/lib/blog/hooks/useBlog' +import { useRouter } from 'next/router' + +export default function BlogDetail() { + const router = useRouter() + const { slug = '' } = router.query + const id = getIdFromSlug(slug) + const { blog } = useBlog({ id }) + + const parsedContent = blog.data?.content?.replaceAll( + 'src="/web/image', + `src="${process.env.NEXT_PUBLIC_ODOO_HOST}/web/image` + ) + + const contentClassNames = ` + prose + prose-gray + prose-a:text-red_r-10 + prose-a:no-underline + prose-p:my-4 + prose-headings:mt-6 + prose-headings:mb-3 + prose-headings:font-medium + prose-h1:text-title-sm + prose-h2:text-h-md + prose-img:my-0 + prose-img:mb-1 + prose-img:inline-block + prose-hr:my-3 + max-w-none + ` + + return ( + <BasicLayout> + <div className='container mx-auto p-4 md:p-0 my-0 md:my-10'> + <h1 className='text-title-sm md:text-title-md font-semibold mb-2 leading-10'> + {blog.data?.title} + </h1> + <h2 className='leading-6 text-gray_r-12/90 mb-8'> + Diposting pada tanggal {blog.data?.postDate}{' '} + {blog.data?.category?.id && `di ${blog.data?.category?.name}`} + </h2> + + <article + className={contentClassNames} + dangerouslySetInnerHTML={{ __html: parsedContent }} + /> + </div> + </BasicLayout> + ) +} diff --git a/src/pages/blog/index.jsx b/src/pages/blog/index.jsx index c755ec82..041fc046 100644 --- a/src/pages/blog/index.jsx +++ b/src/pages/blog/index.jsx @@ -1,74 +1,64 @@ import BasicLayout from '@/core/components/layouts/BasicLayout' -import { Card, Spinner } from 'flowbite-react' import Link from 'next/link' -import { useCallback, useEffect, useState } from 'react' import { createSlug } from '@/core/utils/slug' -import useDevice from '@/core/hooks/useDevice' -import Image from 'next/image' -import odooApi from '@/core/api/odooApi' +import Image from '@/core/components/elements/Image/Image' +import useBlogs from '@/lib/blog/hooks/useBlogs' +import { useRouter } from 'next/router' +import Pagination from '@/core/components/elements/Pagination/Pagination' +import Spinner from '@/core/components/elements/Spinner/Spinner' export default function Blogs() { - const [isLoading, setIsLoading] = useState(true) - const [blogsValues, setBlogs] = useState([]) - const { isMobile } = useDevice() + const router = useRouter() + const limit = 16 - const getBlogs = useCallback(async () => { - // setIsLoading(true) - const result = await odooApi('GET', '/api/v1/blog') - setBlogs(result.blogs) - setIsLoading(false) - }, []) + const { page = 1 } = router.query + const { blogs } = useBlogs({ limit, offset: limit * (page - 1) }) - useEffect(() => { - getBlogs() - }, [getBlogs]) + const pageCount = Math.ceil(blogs?.data?.blogTotal / limit) - if (isLoading) { - return ( - <> - <BasicLayout> - <div className='container mx-auto flex justify-center my-4'> - <Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12 md:w-20 md:mt-28' /> - </div> - </BasicLayout> - </> - ) - } return ( <BasicLayout> - <div className='container mx-auto p-4 md:p-0 mt-0 md:mt-10 mb-3'> - <div> - <h1 className='font-bold text-2xl'>Blog Indoteknik</h1> - </div> - <div className='grid grid-cols-2 gap-4 mt-4 md:grid-cols-4 !overflow-x-hidden'> - {blogsValues?.map((blog, index) => { + <div className='container mx-auto p-4 md:p-0 my-0 md:my-10'> + <h1 className='font-bold text-2xl mb-6'>Blog Indoteknik</h1> + + {blogs.isLoading && ( + <div className='flex justify-center my-6'> + <Spinner className='w-6 text-gray_r-12/50 fill-gray_r-12' /> + </div> + )} + + <div className='grid gap-6 grid-cols-1 md:grid-cols-4'> + {blogs.data?.blogs?.map((blog, index) => { return ( <div className='rounded shadow-sm border border-gray_r-4 h-full bg-white' key={index}> - <Image - src={blog.thumbnail} - alt={blog.title} - width={512} - height={512} - className='w-full h-[112px] object-cover object-center' - /> - <div className='p-2 sm:p-3 pb-3 text-caption-2 sm:text-body-2 leading-5 flex flex-col'> - <Link href='#' className='mb-1 font-normal text-red_r-11'> - {blog.category.name} - </Link> + <Link href={createSlug('blog/', blog.title, blog.id)}> + <Image + src={blog.thumbnail} + alt={blog.title} + className='w-full h-[112px] object-cover object-center' + /> + </Link> + <div className='p-3 text-gray_r-12/80'> + <div className='mb-1'>{blog.category.name}</div> <Link - href='#' - className='mb-2 !text-gray_r-12 text-body-1 font-semibold leading-6 line-clamp-2' + href={createSlug('blog/', blog.title, blog.id)} + className='mb-3 !text-gray_r-12/90 text-body-1 font-medium leading-6 line-clamp-2' > {blog.title} </Link> - <p className='font-normal text-gray-700 dark:text-gray-400 mt-auto'> - {blog.postDate} - </p> + <div className='text-caption-1'>{blog.postDate}</div> </div> </div> ) })} </div> + + <Pagination + currentPage={parseInt(page)} + pageCount={pageCount} + url={`/blog`} + className='mt-4 md:mt-10' + /> </div> </BasicLayout> ) diff --git a/src/pages/video.jsx b/src/pages/video.jsx index c7248da1..c2348091 100644 --- a/src/pages/video.jsx +++ b/src/pages/video.jsx @@ -47,7 +47,7 @@ export default function Video() { currentPage={parseInt(page)} pageCount={pageCount} url={`/video`} - className='mt-10' + className='mt-4 md:mt-10' /> </div> </BasicLayout> |
