From f99e0aba70efad0deb907d8e27f09fc9f527c8a4 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Fri, 17 Feb 2023 17:07:50 +0700 Subject: Refactor --- src/core/api/odooApi.js | 47 +++++++++ src/core/api/searchSuggestApi.js | 12 +++ src/core/components/Seo.jsx | 11 +++ src/core/components/elements/Appbar/Appbar.jsx | 33 +++++++ src/core/components/elements/Badge/Badge.jsx | 33 +++++++ src/core/components/elements/Divider/Divider.jsx | 11 +++ src/core/components/elements/Image/Image.jsx | 15 +++ src/core/components/elements/Link/Link.jsx | 17 ++++ src/core/components/elements/NavBar/NavBar.jsx | 31 ++++++ src/core/components/elements/NavBar/Search.jsx | 89 +++++++++++++++++ .../components/elements/Pagination/Pagination.js | 64 ++++++++++++ src/core/components/elements/Popup/BottomPopup.jsx | 21 ++++ .../components/elements/Skeleton/BrandSkeleton.jsx | 8 ++ .../components/elements/Skeleton/ImageSkeleton.jsx | 10 ++ .../elements/Skeleton/ProductCardSkeleton.jsx | 15 +++ src/core/components/layouts/AnimationLayout.jsx | 22 +++++ src/core/components/layouts/AppLayout.jsx | 15 +++ src/core/components/layouts/BasicLayout.jsx | 15 +++ src/core/hooks/useActive.js | 19 ++++ src/core/hooks/useAuth.js | 14 +++ src/core/utils/address.js | 27 ------ src/core/utils/apiOdoo.js | 44 --------- src/core/utils/auth.js | 37 +++---- src/core/utils/cart.js | 39 ++++---- src/core/utils/convertToOption.js | 11 --- src/core/utils/currencyFormat.js | 10 +- src/core/utils/formValidation.js | 107 --------------------- src/core/utils/getFileBase64.js | 11 --- src/core/utils/greeting.js | 9 -- src/core/utils/mailer.js | 12 --- src/core/utils/slug.js | 24 ++--- src/core/utils/toTitleCase.js | 6 +- 32 files changed, 558 insertions(+), 281 deletions(-) create mode 100644 src/core/api/odooApi.js create mode 100644 src/core/api/searchSuggestApi.js create mode 100644 src/core/components/Seo.jsx create mode 100644 src/core/components/elements/Appbar/Appbar.jsx create mode 100644 src/core/components/elements/Badge/Badge.jsx create mode 100644 src/core/components/elements/Divider/Divider.jsx create mode 100644 src/core/components/elements/Image/Image.jsx create mode 100644 src/core/components/elements/Link/Link.jsx create mode 100644 src/core/components/elements/NavBar/NavBar.jsx create mode 100644 src/core/components/elements/NavBar/Search.jsx create mode 100644 src/core/components/elements/Pagination/Pagination.js create mode 100644 src/core/components/elements/Popup/BottomPopup.jsx create mode 100644 src/core/components/elements/Skeleton/BrandSkeleton.jsx create mode 100644 src/core/components/elements/Skeleton/ImageSkeleton.jsx create mode 100644 src/core/components/elements/Skeleton/ProductCardSkeleton.jsx create mode 100644 src/core/components/layouts/AnimationLayout.jsx create mode 100644 src/core/components/layouts/AppLayout.jsx create mode 100644 src/core/components/layouts/BasicLayout.jsx create mode 100644 src/core/hooks/useActive.js create mode 100644 src/core/hooks/useAuth.js delete mode 100644 src/core/utils/address.js delete mode 100644 src/core/utils/apiOdoo.js delete mode 100644 src/core/utils/convertToOption.js delete mode 100644 src/core/utils/formValidation.js delete mode 100644 src/core/utils/getFileBase64.js delete mode 100644 src/core/utils/greeting.js delete mode 100644 src/core/utils/mailer.js (limited to 'src/core') diff --git a/src/core/api/odooApi.js b/src/core/api/odooApi.js new file mode 100644 index 00000000..59d88faa --- /dev/null +++ b/src/core/api/odooApi.js @@ -0,0 +1,47 @@ +import axios from 'axios' +import camelcaseObjectDeep from 'camelcase-object-deep' +import { getCookie, setCookie } from 'cookies-next' +import { getAuth } from '../utils/auth' + +const renewToken = async () => { + let token = await axios.get(process.env.ODOO_HOST + '/api/token') + setCookie('token', token.data.result) + return token.data.result +} + +const getToken = async () => { + let token = getCookie('token') + if (token == undefined) token = await renewToken() + return token +} + +const maxConnectionAttempt = 15 +let connectionAttempt = 0 + +const odooApi = async (method, url, data = {}, headers = {}) => { + connectionAttempt++ + try { + let token = await getToken() + const auth = getAuth() + + let axiosParameter = { + method, + url: process.env.ODOO_HOST + url, + headers: {'Authorization': token, ...headers} + } + if (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() + + let res = await axios(axiosParameter) + if (res.data.status.code == 401 && connectionAttempt < maxConnectionAttempt) { + await renewToken() + return odooApi(method, url, data, headers) + } + return camelcaseObjectDeep(res.data.result) || [] + } catch (error) { + console.log(error) + } +} + +export default odooApi; \ No newline at end of file diff --git a/src/core/api/searchSuggestApi.js b/src/core/api/searchSuggestApi.js new file mode 100644 index 00000000..b5edebda --- /dev/null +++ b/src/core/api/searchSuggestApi.js @@ -0,0 +1,12 @@ +import axios from "axios" + +const searchSuggestApi = async ({ query }) => { + const dataSearchSuggest = await axios(`${process.env.SELF_HOST}/api/shop/suggest?q=${query.trim()}`) + return dataSearchSuggest +} + +searchSuggestApi.defaultProps = { + query: '' +} + +export default searchSuggestApi \ No newline at end of file diff --git a/src/core/components/Seo.jsx b/src/core/components/Seo.jsx new file mode 100644 index 00000000..bcfaa6ef --- /dev/null +++ b/src/core/components/Seo.jsx @@ -0,0 +1,11 @@ +import Head from "next/head" + +const Seo = ({ title }) => { + return ( + + { title } + + ) +} + +export default Seo \ No newline at end of file diff --git a/src/core/components/elements/Appbar/Appbar.jsx b/src/core/components/elements/Appbar/Appbar.jsx new file mode 100644 index 00000000..0fe087d3 --- /dev/null +++ b/src/core/components/elements/Appbar/Appbar.jsx @@ -0,0 +1,33 @@ +import { useRouter } from "next/router" +import Link from "../Link/Link" +import { HomeIcon, Bars3Icon, ShoppingCartIcon, ChevronLeftIcon } from "@heroicons/react/24/outline" + +const AppBar = ({ title }) => { + const router = useRouter() + + return ( + + ) +} + +export default AppBar \ No newline at end of file diff --git a/src/core/components/elements/Badge/Badge.jsx b/src/core/components/elements/Badge/Badge.jsx new file mode 100644 index 00000000..5d8ebd1c --- /dev/null +++ b/src/core/components/elements/Badge/Badge.jsx @@ -0,0 +1,33 @@ +const Badge = ({ + children, + type, + ...props +}) => { + return ( +
+ { children } +
+ ) +} + +Badge.defaultProps = { + className: '' +} + +const badgeStyle = (type) => { + let className = ['rounded px-1 text-[11px]'] + switch (type) { + case 'solid-red': + className.push('bg-red_r-11 text-white') + break + case 'light': + className.push('bg-gray_r-4 text-gray_r-11') + break + } + return className.join(' ') +} + +export default Badge \ No newline at end of file diff --git a/src/core/components/elements/Divider/Divider.jsx b/src/core/components/elements/Divider/Divider.jsx new file mode 100644 index 00000000..355cd509 --- /dev/null +++ b/src/core/components/elements/Divider/Divider.jsx @@ -0,0 +1,11 @@ +const Divider = (props) => { + return ( +
+ ) +} + +Divider.defaultProps = { + className: '' +} + +export default Divider \ No newline at end of file diff --git a/src/core/components/elements/Image/Image.jsx b/src/core/components/elements/Image/Image.jsx new file mode 100644 index 00000000..be2866e7 --- /dev/null +++ b/src/core/components/elements/Image/Image.jsx @@ -0,0 +1,15 @@ +import { LazyLoadImage } from "react-lazy-load-image-component" +import "react-lazy-load-image-component/src/effects/opacity.css" + +const Image = ({ ...props }) => ( + +) + +Image.defaultProps = LazyLoadImage.defaultProps + +export default Image \ No newline at end of file diff --git a/src/core/components/elements/Link/Link.jsx b/src/core/components/elements/Link/Link.jsx new file mode 100644 index 00000000..a619164d --- /dev/null +++ b/src/core/components/elements/Link/Link.jsx @@ -0,0 +1,17 @@ +import NextLink from "next/link" + +const Link = ({ children, ...props }) => { + return ( + + {children} + + ) +} + +Link.defaultProps = NextLink.defaultProps + +export default Link \ No newline at end of file diff --git a/src/core/components/elements/NavBar/NavBar.jsx b/src/core/components/elements/NavBar/NavBar.jsx new file mode 100644 index 00000000..212fd341 --- /dev/null +++ b/src/core/components/elements/NavBar/NavBar.jsx @@ -0,0 +1,31 @@ +import Image from "next/image" +import IndoteknikLogo from "@/images/logo.png" +import { Bars3Icon, HeartIcon, ShoppingCartIcon } from "@heroicons/react/24/outline" +import Link from "../Link/Link" +import Search from "./Search" + +const NavBar = () => { + return ( + + ) +} + +export default NavBar \ No newline at end of file diff --git a/src/core/components/elements/NavBar/Search.jsx b/src/core/components/elements/NavBar/Search.jsx new file mode 100644 index 00000000..cca1a97c --- /dev/null +++ b/src/core/components/elements/NavBar/Search.jsx @@ -0,0 +1,89 @@ +import searchSuggestApi from "@/core/api/searchSuggestApi" +import { MagnifyingGlassIcon } from "@heroicons/react/24/outline" +import { useCallback, useEffect, useRef, useState } from "react" +import Link from "../Link/Link" +import { useRouter } from "next/router" + +const Search = () => { + const router = useRouter() + const queryRef = useRef() + const [ query, setQuery ] = useState('') + const [ suggestions, setSuggestions ] = useState([]) + + useEffect(() => { + setQuery(router.query.q) + }, [router.query]) + + const loadSuggestion = useCallback(() => { + if (query && document.activeElement == queryRef.current) { + (async () => { + const dataSuggestion = await searchSuggestApi({ query }) + setSuggestions(dataSuggestion.data.suggestions) + })() + return + } else { + setSuggestions([]) + } + }, [ query ]) + + useEffect(() => { + if (query && document.activeElement == queryRef.current) { + loadSuggestion() + } else { + setSuggestions([]) + } + }, [ loadSuggestion, query ]) + + const handleSubmit = (e) => { + e.preventDefault() + if (query) { + router.push(`/shop/search?q=${query}`) + } else { + queryRef.current.focus() + } + } + + const onInputBlur = () => { + setTimeout(() => { + setSuggestions([]) + }, 100) + } + + return ( +
+ setQuery(e.target.value)} + onBlur={onInputBlur} + onFocus={loadSuggestion} + /> + + + { suggestions.length > 1 && ( + <> +
+ {suggestions.map((suggestion, index) => ( + + {suggestion.term} + + ))} +
+ + ) } +
+ ) +} + +export default Search \ No newline at end of file diff --git a/src/core/components/elements/Pagination/Pagination.js b/src/core/components/elements/Pagination/Pagination.js new file mode 100644 index 00000000..485295fe --- /dev/null +++ b/src/core/components/elements/Pagination/Pagination.js @@ -0,0 +1,64 @@ +import Link from "../Link/Link" + +const Pagination = ({ pageCount, currentPage, url, className }) => { + let firstPage = false + let lastPage = false + let dotsPrevPage = false + let dotsNextPage = false + let urlParameterPrefix = url.includes('?') ? '&' : '?' + + return pageCount > 1 && ( +
+ { Array.from(Array(pageCount)).map((v, i) => { + let page = i + 1 + let rangePrevPage = currentPage - 2 + let rangeNextPage = currentPage + 2 + let PageComponent = {page} + let DotsComponent =
...
+ + if (pageCount == 7) { + return PageComponent + } + + if (currentPage == 1) rangeNextPage += 3 + if (currentPage == 2) rangeNextPage += 2 + if (currentPage == 3) rangeNextPage += 1 + if (currentPage == 4) rangePrevPage -= 1 + if (currentPage == pageCount) rangePrevPage -= 3 + if (currentPage == pageCount - 1) rangePrevPage -= 2 + if (currentPage == pageCount - 2) rangePrevPage -= 1 + if (currentPage == pageCount - 3) rangeNextPage += 1 + + if (page > rangePrevPage && page < rangeNextPage) { + return PageComponent + } + + if (page == 1 && rangePrevPage >= 1 && !firstPage) { + firstPage = true + return PageComponent + } + + if (page == pageCount && rangeNextPage <= pageCount && !lastPage) { + lastPage = true + return PageComponent + } + + if (page > currentPage && (pageCount - currentPage) > 1 && !dotsNextPage) { + dotsNextPage = true + return DotsComponent + } + + if (page < currentPage && (currentPage - 1) > 1 && !dotsPrevPage) { + dotsPrevPage = true + return DotsComponent + } + }) } +
+ ) +} + +Pagination.defaultProps = { + className: '' +} + +export default Pagination \ No newline at end of file diff --git a/src/core/components/elements/Popup/BottomPopup.jsx b/src/core/components/elements/Popup/BottomPopup.jsx new file mode 100644 index 00000000..e687cf20 --- /dev/null +++ b/src/core/components/elements/Popup/BottomPopup.jsx @@ -0,0 +1,21 @@ +import { XMarkIcon } from "@heroicons/react/24/outline" + +const BottomPopup = ({ children, active, title, close }) => ( + <> +
+
+
+
{ title }
+ +
+ { children } +
+ +) + +export default BottomPopup \ No newline at end of file diff --git a/src/core/components/elements/Skeleton/BrandSkeleton.jsx b/src/core/components/elements/Skeleton/BrandSkeleton.jsx new file mode 100644 index 00000000..ce5a994d --- /dev/null +++ b/src/core/components/elements/Skeleton/BrandSkeleton.jsx @@ -0,0 +1,8 @@ +const BrandSkeleton = () => ( +
+
+ Loading... +
+) + +export default BrandSkeleton \ No newline at end of file diff --git a/src/core/components/elements/Skeleton/ImageSkeleton.jsx b/src/core/components/elements/Skeleton/ImageSkeleton.jsx new file mode 100644 index 00000000..2cda9536 --- /dev/null +++ b/src/core/components/elements/Skeleton/ImageSkeleton.jsx @@ -0,0 +1,10 @@ +const ImageSkeleton = () => ( +
+
+ +
+ Loading... +
+) + +export default ImageSkeleton \ No newline at end of file diff --git a/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx b/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx new file mode 100644 index 00000000..66b48f79 --- /dev/null +++ b/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx @@ -0,0 +1,15 @@ +const ProductCardSkeleton = () => ( +
+
+ +
+
+
+
+
+
+ Loading... +
+) + +export default ProductCardSkeleton \ No newline at end of file diff --git a/src/core/components/layouts/AnimationLayout.jsx b/src/core/components/layouts/AnimationLayout.jsx new file mode 100644 index 00000000..cdd2d059 --- /dev/null +++ b/src/core/components/layouts/AnimationLayout.jsx @@ -0,0 +1,22 @@ +import { motion } from 'framer-motion' + +const AnimationLayout = ({ children, ...props }) => { + const transition = { + ease: 'easeOut', + duration: 0.3 + } + + return children && ( + + { children } + + ) +} + +export default AnimationLayout \ No newline at end of file diff --git a/src/core/components/layouts/AppLayout.jsx b/src/core/components/layouts/AppLayout.jsx new file mode 100644 index 00000000..7aaa52ca --- /dev/null +++ b/src/core/components/layouts/AppLayout.jsx @@ -0,0 +1,15 @@ +import AppBar from "../elements/Appbar/Appbar" +import AnimationLayout from "./AnimationLayout" + +const AppLayout = ({ children, title }) => { + return ( + <> + + + { children } + + + ) +} + +export default AppLayout \ No newline at end of file diff --git a/src/core/components/layouts/BasicLayout.jsx b/src/core/components/layouts/BasicLayout.jsx new file mode 100644 index 00000000..32c785e5 --- /dev/null +++ b/src/core/components/layouts/BasicLayout.jsx @@ -0,0 +1,15 @@ +import NavBar from "../elements/NavBar/NavBar" +import AnimationLayout from "./AnimationLayout" + +const BasicLayout = ({ children }) => { + return ( + <> + + + { children } + + + ) +} + +export default BasicLayout \ No newline at end of file diff --git a/src/core/hooks/useActive.js b/src/core/hooks/useActive.js new file mode 100644 index 00000000..e3a371cb --- /dev/null +++ b/src/core/hooks/useActive.js @@ -0,0 +1,19 @@ +import { useState } from "react" + +const useActive = () => { + const [ active, setActive ] = useState(false) + + const activate = () => { + setActive(true) + } + + const deactivate = () => { + setActive(false) + } + + return { + activate, deactivate, active + } +} + +export default useActive \ No newline at end of file diff --git a/src/core/hooks/useAuth.js b/src/core/hooks/useAuth.js new file mode 100644 index 00000000..488562f6 --- /dev/null +++ b/src/core/hooks/useAuth.js @@ -0,0 +1,14 @@ +import { getAuth } from "../utils/auth" + +const useAuth = () => { + const [auth, setAuth] = useState(null) + + useEffect(() => { + const handleIsAuthenticated = () => setAuth(getAuth()) + handleIsAuthenticated() + }, []) + + return [auth, setAuth] +} + +export default useAuth \ No newline at end of file diff --git a/src/core/utils/address.js b/src/core/utils/address.js deleted file mode 100644 index c4a19af5..00000000 --- a/src/core/utils/address.js +++ /dev/null @@ -1,27 +0,0 @@ -const getAddress = () => { - const address = localStorage.getItem('address'); - if (address) return JSON.parse(address); - return {}; -} - -const setAddress = (address) => { - localStorage.setItem('address', JSON.stringify(address)); - return true; -} - -const getItemAddress = (key) => { - let address = getAddress(); - return address[key]; -} - -const createOrUpdateItemAddress = (key, value) => { - let address = getAddress(); - address[key] = value; - setAddress(address); - return true; -} - -export { - getItemAddress, - createOrUpdateItemAddress -}; \ No newline at end of file diff --git a/src/core/utils/apiOdoo.js b/src/core/utils/apiOdoo.js deleted file mode 100644 index 4d0adae3..00000000 --- a/src/core/utils/apiOdoo.js +++ /dev/null @@ -1,44 +0,0 @@ -import { getCookie, setCookie } from 'cookies-next'; -import axios from 'axios'; -import { getAuth } from './auth'; - -const renewToken = async () => { - let token = await axios.get(process.env.SELF_HOST + '/api/token'); - setCookie('token', token.data); - return token.data; -}; - -const getToken = async () => { - let token = getCookie('token'); - if (token == undefined) token = await renewToken(); - return token; -}; - -let connectionTry = 0; -const apiOdoo = async (method, url, data = {}, headers = {}) => { - try { - connectionTry++; - let token = await getToken(); - let axiosParameter = { - method, - url: process.env.ODOO_HOST + url, - headers: {'Authorization': token, ...headers} - } - const auth = getAuth(); - - if (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(); - - let res = await axios(axiosParameter); - if (res.data.status.code == 401 && connectionTry < 15) { - await renewToken(); - return apiOdoo(method, url, data, headers); - } - return res.data.result || []; - } catch (error) { - console.log(error) - } -} - -export default apiOdoo; \ No newline at end of file diff --git a/src/core/utils/auth.js b/src/core/utils/auth.js index 62eba2c0..6aeba02b 100644 --- a/src/core/utils/auth.js +++ b/src/core/utils/auth.js @@ -1,38 +1,29 @@ -import { deleteCookie, getCookie, setCookie } from 'cookies-next'; -import { useEffect, useState } from 'react'; +import { + deleteCookie, + getCookie, + setCookie +} from 'cookies-next' const getAuth = () => { - let auth = getCookie('auth'); + let auth = getCookie('auth') if (auth) { - return JSON.parse(auth); + return JSON.parse(auth) } - return false; + return false } const setAuth = (user) => { - setCookie('auth', JSON.stringify(user)); - return true; + setCookie('auth', JSON.stringify(user)) + return true } const deleteAuth = () => { - deleteCookie('auth'); - return true; -} - -const useAuth = () => { - const [auth, setAuth] = useState(null); - - useEffect(() => { - const handleIsAuthenticated = () => setAuth(getAuth()); - handleIsAuthenticated(); - }, []); - - return [auth, setAuth]; + deleteCookie('auth') + return true } export { getAuth, setAuth, - deleteAuth, - useAuth -}; \ No newline at end of file + deleteAuth +} \ No newline at end of file diff --git a/src/core/utils/cart.js b/src/core/utils/cart.js index 66efcbf2..291d511b 100644 --- a/src/core/utils/cart.js +++ b/src/core/utils/cart.js @@ -1,36 +1,37 @@ const getCart = () => { - const cart = localStorage.getItem('cart'); - if (cart) return JSON.parse(cart); - return {}; + const cart = localStorage.getItem('cart') + if (cart) return JSON.parse(cart) + return {} } const setCart = (cart) => { - localStorage.setItem('cart', JSON.stringify(cart)); - return true; + localStorage.setItem('cart', JSON.stringify(cart)) + return true } -const getItemCart = (product_id) => { - let cart = getCart(); - return cart[product_id]; +const getItemCart = ({ productId }) => { + let cart = getCart() + return cart[productId] } -const createOrUpdateItemCart = (product_id, quantity, selected = false) => { - let cart = getCart(); - cart[product_id] = { product_id, quantity, selected }; - setCart(cart); - return true; +const addItemCart = ({ productId, quantity, selected = false }) => { + let cart = getCart() + quantity = parseInt(quantity) + cart[productId] = { productId, quantity, selected } + setCart(cart) + return true } -const deleteItemCart = (product_id) => { - let cart = getCart(); - delete cart[product_id]; - setCart(cart); - return true; +const deleteItemCart = ({ productId }) => { + let cart = getCart() + delete cart[productId] + setCart(cart) + return true } export { getCart, getItemCart, - createOrUpdateItemCart, + addItemCart, deleteItemCart } \ No newline at end of file diff --git a/src/core/utils/convertToOption.js b/src/core/utils/convertToOption.js deleted file mode 100644 index 08fec08f..00000000 --- a/src/core/utils/convertToOption.js +++ /dev/null @@ -1,11 +0,0 @@ -const convertToOption = (data) => { - if (data) { - return { - value: data.id, - label: data.name, - } - } - return null; -}; - -export default convertToOption; \ No newline at end of file diff --git a/src/core/utils/currencyFormat.js b/src/core/utils/currencyFormat.js index dadeaec6..31f4a8dc 100644 --- a/src/core/utils/currencyFormat.js +++ b/src/core/utils/currencyFormat.js @@ -1,8 +1,10 @@ -export default function currencyFormat(value) { +const currencyFormat = (value) => { const currency = new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', maximumFractionDigits: 0 - }); - return currency.format(value); -} \ No newline at end of file + }) + return currency.format(value) +} + +export default currencyFormat \ No newline at end of file diff --git a/src/core/utils/formValidation.js b/src/core/utils/formValidation.js deleted file mode 100644 index 0e83f4cc..00000000 --- a/src/core/utils/formValidation.js +++ /dev/null @@ -1,107 +0,0 @@ -import { useCallback, useEffect, useState } from "react"; - -const validateForm = (data, queries, hasChangedInputs = null) => { - let result = { valid: true, errors: {} }; - - for (const query in queries) { - if (!hasChangedInputs || (hasChangedInputs && hasChangedInputs[query])) { - const value = data[query]; - const rules = queries[query]; - let errors = []; - let label = null; - for (const rule of rules) { - let emailValidationRegex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - if (rule.startsWith('label:')) { - label = rule.replace('label:', ''); - } else if (rule === 'required' && !value) { - errors.push('tidak boleh kosong'); - } else if (rule === 'email' && !value.match(emailValidationRegex)) { - errors.push('harus format johndoe@example.com'); - } else if (rule.startsWith('maxLength:')) { - let maxLength = parseInt(rule.replace('maxLength:', '')); - if (value && value.length > maxLength) errors.push(`maksimal ${maxLength} karakter`); - } - } - if (errors.length > 0) { - result.errors[query] = (label || query) + ' ' + errors.join(', '); - } - } - } - - if (Object.keys(result.errors).length > 0) { - result.valid = false; - } - - return result; -} - -const useFormValidation = ({ initialFormValue = {}, validationScheme = {} }) => { - const [ formInputs, setFormInputs ] = useState(initialFormValue); - const [ formErrors, setFormErrors ] = useState({}); - const [ formValidation ] = useState(validationScheme); - const [ hasChangedInputs, setHasChangedInputs ] = useState({}); - - const handleFormSubmit = (event, func) => { - if (event) { - event.preventDefault(); - - // Make all input to be has changed mode to revalidate - const changedInputs = {}; - for (const key in formInputs) changedInputs[key] = true; - setHasChangedInputs(changedInputs); - - const { valid, errors } = validateForm(formInputs, formValidation, changedInputs); - setFormErrors(errors); - - if (valid) func(); - } - }; - - const setChangedInput = (name, value = true) => { - setHasChangedInputs((hasChangedInputs) => ({ - ...hasChangedInputs, - [name]: value - })); - }; - - const handleInputChange = (event) => { - setFormInputs((formInputs) => ({ - ...formInputs, - [event.target.name]: event.target.value - })); - setChangedInput(event.target.name); - }; - - const handleSelectChange = useCallback((name, value) => { - setFormInputs((formInputs) => ({ - ...formInputs, - [name]: value - })); - setChangedInput(name); - }, []); - - const handleFormReset = () => { - setFormInputs(initialFormValue); - setFormErrors({}); - setHasChangedInputs({}); - } - - useEffect(() => { - if (formInputs) { - const { errors } = validateForm(formInputs, formValidation, hasChangedInputs); - setFormErrors(errors); - } - }, [ formInputs, formValidation, hasChangedInputs ]) - - return { - handleFormReset, - handleFormSubmit, - handleInputChange, - handleSelectChange, - hasChangedInputs, - formInputs, - formErrors - }; - }; - -export default useFormValidation; \ No newline at end of file diff --git a/src/core/utils/getFileBase64.js b/src/core/utils/getFileBase64.js deleted file mode 100644 index 78013e43..00000000 --- a/src/core/utils/getFileBase64.js +++ /dev/null @@ -1,11 +0,0 @@ -const getFileBase64 = file => new Promise((resolve, reject) => { - let reader = new FileReader(); - reader.readAsBinaryString(file); - reader.onload = () => { - let result = reader.result; - resolve(btoa(result)); - }; - reader.onerror = error => reject(error); -}); - -export default getFileBase64; \ No newline at end of file diff --git a/src/core/utils/greeting.js b/src/core/utils/greeting.js deleted file mode 100644 index 7dc19f8f..00000000 --- a/src/core/utils/greeting.js +++ /dev/null @@ -1,9 +0,0 @@ -const greeting = () => { - let hours = new Date().getHours(); - if (hours < 11) return 'Selamat Pagi'; - if (hours < 15) return 'Selamat Siang'; - if (hours < 18) return 'Selamat Sore'; - return 'Selamat Malam'; -} - -export default greeting; \ No newline at end of file diff --git a/src/core/utils/mailer.js b/src/core/utils/mailer.js deleted file mode 100644 index 4e7ff7cc..00000000 --- a/src/core/utils/mailer.js +++ /dev/null @@ -1,12 +0,0 @@ -const nodemailer = require('nodemailer'); -const mailer = nodemailer.createTransport({ - port: process.env.MAIL_PORT, - host: process.env.MAIL_HOST, - auth: { - user: process.env.MAIL_USER, - pass: process.env.MAIL_PASS - }, - secure: true -}); - -export default mailer; \ No newline at end of file diff --git a/src/core/utils/slug.js b/src/core/utils/slug.js index 0a7d30fc..fab37330 100644 --- a/src/core/utils/slug.js +++ b/src/core/utils/slug.js @@ -1,25 +1,25 @@ -import toTitleCase from './toTitleCase'; +import toTitleCase from './toTitleCase' -const createSlug = (name, id) => { - let slug = name?.trim().replace(new RegExp(/[^A-Za-z0-9]/, 'g'), '-').toLowerCase() + '-' + id; - let splitSlug = slug.split('-'); - let filterSlugFromEmptyChar = splitSlug.filter(x => x != ''); - return filterSlugFromEmptyChar.join('-'); +const createSlug = (prefix, name, id) => { + let slug = name?.trim().replace(new RegExp(/[^A-Za-z0-9]/, 'g'), '-').toLowerCase() + '-' + id + let splitSlug = slug.split('-') + let filterSlugFromEmptyChar = splitSlug.filter(x => x != '') + return prefix + filterSlugFromEmptyChar.join('-') } const getIdFromSlug = (slug) => { - let id = slug.split('-'); - return id[id.length-1]; + let id = slug.split('-') + return id[id.length-1] } const getNameFromSlug = (slug) => { - let name = slug.split('-'); - name.pop(); - return toTitleCase(name.join(' ')); + let name = slug.split('-') + name.pop() + return toTitleCase(name.join(' ')) } export { createSlug, getIdFromSlug, getNameFromSlug -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/core/utils/toTitleCase.js b/src/core/utils/toTitleCase.js index 5cfd70d0..b2751f0b 100644 --- a/src/core/utils/toTitleCase.js +++ b/src/core/utils/toTitleCase.js @@ -1,8 +1,10 @@ -export default function toTitleCase(str) { +const toTitleCase = (str) => { return str.replace( /\w\S*/g, function(txt) { return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); } ); -} \ No newline at end of file +} + +export default toTitleCase \ No newline at end of file -- cgit v1.2.3 From 8c38ac6b55ce3aa15196364619f8f22053a00c48 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Sat, 18 Feb 2023 01:15:17 +0700 Subject: fix build --- src/core/utils/cart.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'src/core') diff --git a/src/core/utils/cart.js b/src/core/utils/cart.js index 291d511b..928d2ad1 100644 --- a/src/core/utils/cart.js +++ b/src/core/utils/cart.js @@ -1,11 +1,15 @@ const getCart = () => { - const cart = localStorage.getItem('cart') - if (cart) return JSON.parse(cart) + if (typeof window !== 'undefined') { + const cart = localStorage.getItem('cart') + if (cart) return JSON.parse(cart) + } return {} } const setCart = (cart) => { - localStorage.setItem('cart', JSON.stringify(cart)) + if (typeof window !== 'undefined') { + localStorage.setItem('cart', JSON.stringify(cart)) + } return true } -- cgit v1.2.3 From 69f55de26319e570ce0a8c4dbe8a29cb0d0b51c5 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Sat, 18 Feb 2023 22:03:55 +0700 Subject: optimization --- src/core/components/elements/Image/Image.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/core') diff --git a/src/core/components/elements/Image/Image.jsx b/src/core/components/elements/Image/Image.jsx index be2866e7..579660a4 100644 --- a/src/core/components/elements/Image/Image.jsx +++ b/src/core/components/elements/Image/Image.jsx @@ -4,9 +4,10 @@ import "react-lazy-load-image-component/src/effects/opacity.css" const Image = ({ ...props }) => ( ) -- cgit v1.2.3 From 347e28848fb063ffcb7f9268384409e57b7ef3ad Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Sat, 18 Feb 2023 22:08:07 +0700 Subject: change animation --- src/core/components/layouts/AnimationLayout.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core') diff --git a/src/core/components/layouts/AnimationLayout.jsx b/src/core/components/layouts/AnimationLayout.jsx index cdd2d059..12b6d112 100644 --- a/src/core/components/layouts/AnimationLayout.jsx +++ b/src/core/components/layouts/AnimationLayout.jsx @@ -8,9 +8,9 @@ const AnimationLayout = ({ children, ...props }) => { return children && ( -- cgit v1.2.3 From 75767ed41d28947429f3dbef9c7e128ebc552e64 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Sat, 18 Feb 2023 22:18:46 +0700 Subject: change animation --- src/core/components/layouts/AnimationLayout.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core') diff --git a/src/core/components/layouts/AnimationLayout.jsx b/src/core/components/layouts/AnimationLayout.jsx index 12b6d112..f40f1eec 100644 --- a/src/core/components/layouts/AnimationLayout.jsx +++ b/src/core/components/layouts/AnimationLayout.jsx @@ -8,7 +8,7 @@ const AnimationLayout = ({ children, ...props }) => { return children && ( Date: Sat, 18 Feb 2023 22:21:46 +0700 Subject: change animation --- src/core/components/layouts/AnimationLayout.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core') diff --git a/src/core/components/layouts/AnimationLayout.jsx b/src/core/components/layouts/AnimationLayout.jsx index f40f1eec..adb6b081 100644 --- a/src/core/components/layouts/AnimationLayout.jsx +++ b/src/core/components/layouts/AnimationLayout.jsx @@ -8,9 +8,9 @@ const AnimationLayout = ({ children, ...props }) => { return children && ( -- cgit v1.2.3 From d0d2a927fa1b9ac0a0e571f6e6f1294445db66a4 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Sun, 19 Feb 2023 22:06:00 +0700 Subject: fix --- src/core/components/elements/NavBar/NavBar.jsx | 31 --------- src/core/components/elements/NavBar/Search.jsx | 89 ------------------------ src/core/components/elements/Sidebar/Sidebar.jsx | 30 ++++++++ src/core/components/layouts/BasicLayout.jsx | 4 +- src/core/hooks/useSidebar.js | 22 ++++++ 5 files changed, 54 insertions(+), 122 deletions(-) delete mode 100644 src/core/components/elements/NavBar/NavBar.jsx delete mode 100644 src/core/components/elements/NavBar/Search.jsx create mode 100644 src/core/components/elements/Sidebar/Sidebar.jsx create mode 100644 src/core/hooks/useSidebar.js (limited to 'src/core') diff --git a/src/core/components/elements/NavBar/NavBar.jsx b/src/core/components/elements/NavBar/NavBar.jsx deleted file mode 100644 index 212fd341..00000000 --- a/src/core/components/elements/NavBar/NavBar.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import Image from "next/image" -import IndoteknikLogo from "@/images/logo.png" -import { Bars3Icon, HeartIcon, ShoppingCartIcon } from "@heroicons/react/24/outline" -import Link from "../Link/Link" -import Search from "./Search" - -const NavBar = () => { - return ( - - ) -} - -export default NavBar \ No newline at end of file diff --git a/src/core/components/elements/NavBar/Search.jsx b/src/core/components/elements/NavBar/Search.jsx deleted file mode 100644 index cca1a97c..00000000 --- a/src/core/components/elements/NavBar/Search.jsx +++ /dev/null @@ -1,89 +0,0 @@ -import searchSuggestApi from "@/core/api/searchSuggestApi" -import { MagnifyingGlassIcon } from "@heroicons/react/24/outline" -import { useCallback, useEffect, useRef, useState } from "react" -import Link from "../Link/Link" -import { useRouter } from "next/router" - -const Search = () => { - const router = useRouter() - const queryRef = useRef() - const [ query, setQuery ] = useState('') - const [ suggestions, setSuggestions ] = useState([]) - - useEffect(() => { - setQuery(router.query.q) - }, [router.query]) - - const loadSuggestion = useCallback(() => { - if (query && document.activeElement == queryRef.current) { - (async () => { - const dataSuggestion = await searchSuggestApi({ query }) - setSuggestions(dataSuggestion.data.suggestions) - })() - return - } else { - setSuggestions([]) - } - }, [ query ]) - - useEffect(() => { - if (query && document.activeElement == queryRef.current) { - loadSuggestion() - } else { - setSuggestions([]) - } - }, [ loadSuggestion, query ]) - - const handleSubmit = (e) => { - e.preventDefault() - if (query) { - router.push(`/shop/search?q=${query}`) - } else { - queryRef.current.focus() - } - } - - const onInputBlur = () => { - setTimeout(() => { - setSuggestions([]) - }, 100) - } - - return ( -
- setQuery(e.target.value)} - onBlur={onInputBlur} - onFocus={loadSuggestion} - /> - - - { suggestions.length > 1 && ( - <> -
- {suggestions.map((suggestion, index) => ( - - {suggestion.term} - - ))} -
- - ) } -
- ) -} - -export default Search \ No newline at end of file diff --git a/src/core/components/elements/Sidebar/Sidebar.jsx b/src/core/components/elements/Sidebar/Sidebar.jsx new file mode 100644 index 00000000..249ccbce --- /dev/null +++ b/src/core/components/elements/Sidebar/Sidebar.jsx @@ -0,0 +1,30 @@ +import Link from "../Link/Link" + +const Sidebar = ({ + active, + close +}) => { + return ( + <> + { active &&
} +
+
+ + Semua Brand + + + Tentang Indoteknik + + + Pusat Bantuan + + + Kategori + +
+
+ + ) +} + +export default Sidebar \ No newline at end of file diff --git a/src/core/components/layouts/BasicLayout.jsx b/src/core/components/layouts/BasicLayout.jsx index 32c785e5..94c235fb 100644 --- a/src/core/components/layouts/BasicLayout.jsx +++ b/src/core/components/layouts/BasicLayout.jsx @@ -1,10 +1,10 @@ -import NavBar from "../elements/NavBar/NavBar" +import Navbar from "../elements/Navbar/Navbar" import AnimationLayout from "./AnimationLayout" const BasicLayout = ({ children }) => { return ( <> - + { children } diff --git a/src/core/hooks/useSidebar.js b/src/core/hooks/useSidebar.js new file mode 100644 index 00000000..9388734a --- /dev/null +++ b/src/core/hooks/useSidebar.js @@ -0,0 +1,22 @@ +import useActive from "./useActive" +import SidebarComponent from "../components/elements/Sidebar/Sidebar" +import { useEffect } from "react" + +const useSidebar = () => { + const { active, activate, deactivate } = useActive() + + useEffect(() => { + if (active) { + document.querySelector('html, body').classList.add('overflow-hidden') + } else { + document.querySelector('html, body').classList.remove('overflow-hidden') + } + }, [active]) + + return { + open: activate, + Sidebar: + } +} + +export default useSidebar \ No newline at end of file -- cgit v1.2.3 From 7bb1e940336f306f4755ec9d05dd6c1f29232b23 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Sun, 19 Feb 2023 22:07:29 +0700 Subject: change navbar --- src/core/components/elements/Navbar/Navbar.jsx | 36 +++++++++++ src/core/components/elements/Navbar/Search.jsx | 89 ++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 src/core/components/elements/Navbar/Navbar.jsx create mode 100644 src/core/components/elements/Navbar/Search.jsx (limited to 'src/core') diff --git a/src/core/components/elements/Navbar/Navbar.jsx b/src/core/components/elements/Navbar/Navbar.jsx new file mode 100644 index 00000000..e7f447eb --- /dev/null +++ b/src/core/components/elements/Navbar/Navbar.jsx @@ -0,0 +1,36 @@ +import Image from "next/image" +import IndoteknikLogo from "@/images/logo.png" +import { Bars3Icon, HeartIcon, ShoppingCartIcon } from "@heroicons/react/24/outline" +import Link from "../Link/Link" +import Search from "./Search" +import useSidebar from "@/core/hooks/useSidebar" + +const Navbar = () => { + const { Sidebar, open } = useSidebar() + return ( + <> + + { Sidebar } + + ) +} + +export default Navbar \ No newline at end of file diff --git a/src/core/components/elements/Navbar/Search.jsx b/src/core/components/elements/Navbar/Search.jsx new file mode 100644 index 00000000..cca1a97c --- /dev/null +++ b/src/core/components/elements/Navbar/Search.jsx @@ -0,0 +1,89 @@ +import searchSuggestApi from "@/core/api/searchSuggestApi" +import { MagnifyingGlassIcon } from "@heroicons/react/24/outline" +import { useCallback, useEffect, useRef, useState } from "react" +import Link from "../Link/Link" +import { useRouter } from "next/router" + +const Search = () => { + const router = useRouter() + const queryRef = useRef() + const [ query, setQuery ] = useState('') + const [ suggestions, setSuggestions ] = useState([]) + + useEffect(() => { + setQuery(router.query.q) + }, [router.query]) + + const loadSuggestion = useCallback(() => { + if (query && document.activeElement == queryRef.current) { + (async () => { + const dataSuggestion = await searchSuggestApi({ query }) + setSuggestions(dataSuggestion.data.suggestions) + })() + return + } else { + setSuggestions([]) + } + }, [ query ]) + + useEffect(() => { + if (query && document.activeElement == queryRef.current) { + loadSuggestion() + } else { + setSuggestions([]) + } + }, [ loadSuggestion, query ]) + + const handleSubmit = (e) => { + e.preventDefault() + if (query) { + router.push(`/shop/search?q=${query}`) + } else { + queryRef.current.focus() + } + } + + const onInputBlur = () => { + setTimeout(() => { + setSuggestions([]) + }, 100) + } + + return ( +
+ setQuery(e.target.value)} + onBlur={onInputBlur} + onFocus={loadSuggestion} + /> + + + { suggestions.length > 1 && ( + <> +
+ {suggestions.map((suggestion, index) => ( + + {suggestion.term} + + ))} +
+ + ) } +
+ ) +} + +export default Search \ No newline at end of file -- cgit v1.2.3 From 71ca8757d549c62e7b2925793689815f4ab771ad Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Sun, 19 Feb 2023 22:18:01 +0700 Subject: fix --- src/core/components/elements/Navbar/Navbar.jsx | 4 +++- src/core/components/layouts/BasicLayout.jsx | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/core') diff --git a/src/core/components/elements/Navbar/Navbar.jsx b/src/core/components/elements/Navbar/Navbar.jsx index e7f447eb..99fdc446 100644 --- a/src/core/components/elements/Navbar/Navbar.jsx +++ b/src/core/components/elements/Navbar/Navbar.jsx @@ -1,10 +1,12 @@ +import dynamic from "next/dynamic" import Image from "next/image" import IndoteknikLogo from "@/images/logo.png" import { Bars3Icon, HeartIcon, ShoppingCartIcon } from "@heroicons/react/24/outline" import Link from "../Link/Link" -import Search from "./Search" import useSidebar from "@/core/hooks/useSidebar" +const Search = dynamic(() => import("./Search")) + const Navbar = () => { const { Sidebar, open } = useSidebar() return ( diff --git a/src/core/components/layouts/BasicLayout.jsx b/src/core/components/layouts/BasicLayout.jsx index 94c235fb..98134b32 100644 --- a/src/core/components/layouts/BasicLayout.jsx +++ b/src/core/components/layouts/BasicLayout.jsx @@ -1,5 +1,7 @@ -import Navbar from "../elements/Navbar/Navbar" -import AnimationLayout from "./AnimationLayout" +import dynamic from "next/dynamic" + +const Navbar = dynamic(() => import("../elements/Navbar/Navbar")) +const AnimationLayout = dynamic(() => import("./AnimationLayout")) const BasicLayout = ({ children }) => { return ( -- cgit v1.2.3 From d22df6bd30b8ed4bcfa938dcbbedc5fc376c2304 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Mon, 20 Feb 2023 10:49:35 +0700 Subject: cart refactor --- src/core/components/elements/Appbar/Appbar.jsx | 2 +- src/core/utils/cart.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/core') diff --git a/src/core/components/elements/Appbar/Appbar.jsx b/src/core/components/elements/Appbar/Appbar.jsx index 0fe087d3..2a19ec6c 100644 --- a/src/core/components/elements/Appbar/Appbar.jsx +++ b/src/core/components/elements/Appbar/Appbar.jsx @@ -6,7 +6,7 @@ const AppBar = ({ title }) => { const router = useRouter() return ( -
diff --git a/src/core/components/layouts/AnimationLayout.jsx b/src/core/components/layouts/AnimationLayout.jsx index adb6b081..cf2b06d5 100644 --- a/src/core/components/layouts/AnimationLayout.jsx +++ b/src/core/components/layouts/AnimationLayout.jsx @@ -2,7 +2,7 @@ import { motion } from 'framer-motion' const AnimationLayout = ({ children, ...props }) => { const transition = { - ease: 'easeOut', + ease: 'easeIn', duration: 0.3 } diff --git a/src/core/components/layouts/AppLayout.jsx b/src/core/components/layouts/AppLayout.jsx index 7aaa52ca..3e986477 100644 --- a/src/core/components/layouts/AppLayout.jsx +++ b/src/core/components/layouts/AppLayout.jsx @@ -4,8 +4,8 @@ import AnimationLayout from "./AnimationLayout" const AppLayout = ({ children, title }) => { return ( <> - + { children } diff --git a/src/core/hooks/useAuth.js b/src/core/hooks/useAuth.js index 488562f6..13f04454 100644 --- a/src/core/hooks/useAuth.js +++ b/src/core/hooks/useAuth.js @@ -1,3 +1,4 @@ +import { useEffect, useState } from "react" import { getAuth } from "../utils/auth" const useAuth = () => { @@ -8,7 +9,7 @@ const useAuth = () => { handleIsAuthenticated() }, []) - return [auth, setAuth] + return auth } export default useAuth \ No newline at end of file -- cgit v1.2.3 From 4fd738fd54f81fa53c2b3e78b7a80fbfda250352 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 21 Feb 2023 10:19:32 +0700 Subject: fix --- src/core/components/elements/Popup/BottomPopup.jsx | 52 ++++++++--- src/core/components/elements/Sidebar/Sidebar.jsx | 103 +++++++++++++-------- 2 files changed, 100 insertions(+), 55 deletions(-) (limited to 'src/core') diff --git a/src/core/components/elements/Popup/BottomPopup.jsx b/src/core/components/elements/Popup/BottomPopup.jsx index 5deceadf..933a8f11 100644 --- a/src/core/components/elements/Popup/BottomPopup.jsx +++ b/src/core/components/elements/Popup/BottomPopup.jsx @@ -1,20 +1,44 @@ import { XMarkIcon } from "@heroicons/react/24/outline" +import { AnimatePresence, motion } from "framer-motion" -const BottomPopup = ({ children, active, title, close }) => ( +const transition = { ease: 'linear', duration: 0.2 } + +const BottomPopup = ({ + children, + active = false, + title, + close +}) => ( <> -
-
-
-
{ title }
- -
- { children } -
+ + { active && ( + <> + + +
+
{ title }
+ +
+ { children } +
+ + ) } +
) diff --git a/src/core/components/elements/Sidebar/Sidebar.jsx b/src/core/components/elements/Sidebar/Sidebar.jsx index 412ed915..122a10f3 100644 --- a/src/core/components/elements/Sidebar/Sidebar.jsx +++ b/src/core/components/elements/Sidebar/Sidebar.jsx @@ -2,6 +2,7 @@ import Link from "../Link/Link" import greeting from "@/core/utils/greeting" import { Cog6ToothIcon } from "@heroicons/react/24/solid" import useAuth from "@/core/hooks/useAuth" +import { AnimatePresence, motion } from "framer-motion" const Sidebar = ({ active, @@ -17,49 +18,69 @@ const Sidebar = ({ ) const itemClassName = 'px-4 py-3 block !text-gray_r-12/80 font-normal' - + const transition = { ease: 'linear', duration: 0.1 } + return ( <> - { active &&
} -
-
-
- { !auth && ( - <> - Daftar - Masuk - - ) } - { auth && ( - <> -
- { greeting() }, - - { auth?.name } - -
- - - - - ) } -
- - Semua Brand - - - Tentang Indoteknik - - - Pusat Bantuan - - -
-
+ + { active && ( + <> + + +
+
+ { !auth && ( + <> + Daftar + Masuk + + ) } + { auth && ( + <> +
+ { greeting() }, + + { auth?.name } + +
+ + + + + ) } +
+ + Semua Brand + + + Tentang Indoteknik + + + Pusat Bantuan + + +
+
+ + ) } +
) } -- cgit v1.2.3 From 488f323e4441b75244785cb66b018f1179b262de Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 21 Feb 2023 10:31:23 +0700 Subject: fix --- src/core/components/elements/Popup/BottomPopup.jsx | 77 ++++++++------ src/core/components/elements/Sidebar/Sidebar.jsx | 116 ++++++++++----------- 2 files changed, 102 insertions(+), 91 deletions(-) (limited to 'src/core') diff --git a/src/core/components/elements/Popup/BottomPopup.jsx b/src/core/components/elements/Popup/BottomPopup.jsx index 933a8f11..c3c380c0 100644 --- a/src/core/components/elements/Popup/BottomPopup.jsx +++ b/src/core/components/elements/Popup/BottomPopup.jsx @@ -1,5 +1,6 @@ import { XMarkIcon } from "@heroicons/react/24/outline" import { AnimatePresence, motion } from "framer-motion" +import { useEffect } from "react" const transition = { ease: 'linear', duration: 0.2 } @@ -8,38 +9,48 @@ const BottomPopup = ({ active = false, title, close -}) => ( - <> - - { active && ( - <> - - -
-
{ title }
- -
- { children } -
- - ) } -
- -) +}) => { + useEffect(() => { + if (active) { + document.querySelector('html, body').classList.add('overflow-hidden') + } else { + document.querySelector('html, body').classList.remove('overflow-hidden') + } + }, [active]) + + return ( + <> + + { active && ( + <> + + +
+
{ title }
+ +
+ { children } +
+ + ) } +
+ + ) +} export default BottomPopup \ No newline at end of file diff --git a/src/core/components/elements/Sidebar/Sidebar.jsx b/src/core/components/elements/Sidebar/Sidebar.jsx index 122a10f3..e81d6130 100644 --- a/src/core/components/elements/Sidebar/Sidebar.jsx +++ b/src/core/components/elements/Sidebar/Sidebar.jsx @@ -22,65 +22,65 @@ const Sidebar = ({ return ( <> - - { active && ( - <> - - -
-
- { !auth && ( - <> - Daftar - Masuk - - ) } - { auth && ( - <> -
- { greeting() }, - - { auth?.name } - -
- - - - - ) } + + { active && ( + <> + + +
+
+ { !auth && ( + <> + Daftar + Masuk + + ) } + { auth && ( + <> +
+ { greeting() }, + + { auth?.name } + +
+ + + + + ) } +
+ + Semua Brand + + + Tentang Indoteknik + + + Pusat Bantuan + +
- - Semua Brand - - - Tentang Indoteknik - - - Pusat Bantuan - - -
- - - ) } - + + + ) } + ) } -- cgit v1.2.3 From fa45f8bc91adef3bacd3460ef4e3b1151ee13e71 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 21 Feb 2023 10:32:09 +0700 Subject: fix --- src/core/components/elements/Sidebar/Sidebar.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core') diff --git a/src/core/components/elements/Sidebar/Sidebar.jsx b/src/core/components/elements/Sidebar/Sidebar.jsx index e81d6130..88de1c1c 100644 --- a/src/core/components/elements/Sidebar/Sidebar.jsx +++ b/src/core/components/elements/Sidebar/Sidebar.jsx @@ -18,7 +18,7 @@ const Sidebar = ({ ) const itemClassName = 'px-4 py-3 block !text-gray_r-12/80 font-normal' - const transition = { ease: 'linear', duration: 0.1 } + const transition = { ease: 'linear', duration: 0.2 } return ( <> -- cgit v1.2.3 From fdfb47c3a825258b871ac5921605642e5e05fdd8 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 21 Feb 2023 12:04:20 +0700 Subject: fix --- src/core/components/elements/Appbar/Appbar.jsx | 2 +- src/core/utils/getFileBase64.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 src/core/utils/getFileBase64.js (limited to 'src/core') diff --git a/src/core/components/elements/Appbar/Appbar.jsx b/src/core/components/elements/Appbar/Appbar.jsx index 8d060c44..8fa5a2a7 100644 --- a/src/core/components/elements/Appbar/Appbar.jsx +++ b/src/core/components/elements/Appbar/Appbar.jsx @@ -22,7 +22,7 @@ const AppBar = ({ title }) => { - +
diff --git a/src/core/utils/getFileBase64.js b/src/core/utils/getFileBase64.js new file mode 100644 index 00000000..78013e43 --- /dev/null +++ b/src/core/utils/getFileBase64.js @@ -0,0 +1,11 @@ +const getFileBase64 = file => new Promise((resolve, reject) => { + let reader = new FileReader(); + reader.readAsBinaryString(file); + reader.onload = () => { + let result = reader.result; + resolve(btoa(result)); + }; + reader.onerror = error => reject(error); +}); + +export default getFileBase64; \ No newline at end of file -- cgit v1.2.3 From de7361718def0f6bb32294bb074841ba2c0a3ce6 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 21 Feb 2023 16:25:35 +0700 Subject: fix --- src/core/components/elements/Appbar/Appbar.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core') diff --git a/src/core/components/elements/Appbar/Appbar.jsx b/src/core/components/elements/Appbar/Appbar.jsx index 8fa5a2a7..36df9edb 100644 --- a/src/core/components/elements/Appbar/Appbar.jsx +++ b/src/core/components/elements/Appbar/Appbar.jsx @@ -11,7 +11,7 @@ const AppBar = ({ title }) => { -
+
{ title }
-- cgit v1.2.3 From 5933732a74ae1ca4124ddd4e8265b1f443234736 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 21 Feb 2023 21:51:51 +0700 Subject: fix --- src/core/components/elements/Image/Image.jsx | 16 +++++++++------- src/core/components/elements/Sidebar/Sidebar.jsx | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'src/core') diff --git a/src/core/components/elements/Image/Image.jsx b/src/core/components/elements/Image/Image.jsx index 579660a4..a6f0b00c 100644 --- a/src/core/components/elements/Image/Image.jsx +++ b/src/core/components/elements/Image/Image.jsx @@ -2,13 +2,15 @@ import { LazyLoadImage } from "react-lazy-load-image-component" import "react-lazy-load-image-component/src/effects/opacity.css" const Image = ({ ...props }) => ( - + <> + + ) Image.defaultProps = LazyLoadImage.defaultProps diff --git a/src/core/components/elements/Sidebar/Sidebar.jsx b/src/core/components/elements/Sidebar/Sidebar.jsx index 88de1c1c..c840a688 100644 --- a/src/core/components/elements/Sidebar/Sidebar.jsx +++ b/src/core/components/elements/Sidebar/Sidebar.jsx @@ -44,8 +44,8 @@ const Sidebar = ({
{ !auth && ( <> - Daftar - Masuk + Daftar + Masuk ) } { auth && ( -- cgit v1.2.3 From 706088ffe9e13221207837bb658887645e76b3ed Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 21 Feb 2023 21:59:24 +0700 Subject: fix --- src/core/components/elements/Navbar/Navbar.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core') diff --git a/src/core/components/elements/Navbar/Navbar.jsx b/src/core/components/elements/Navbar/Navbar.jsx index 99fdc446..f10ebd63 100644 --- a/src/core/components/elements/Navbar/Navbar.jsx +++ b/src/core/components/elements/Navbar/Navbar.jsx @@ -17,9 +17,9 @@ const Navbar = () => { Indoteknik Logo
- + -- cgit v1.2.3 From 98c8fc56db91664b98a50e9113787b56fe785b9e Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 21 Feb 2023 22:33:32 +0700 Subject: fix --- src/core/utils/address.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/core/utils/address.js (limited to 'src/core') diff --git a/src/core/utils/address.js b/src/core/utils/address.js new file mode 100644 index 00000000..b89dd924 --- /dev/null +++ b/src/core/utils/address.js @@ -0,0 +1,31 @@ +const getAddress = () => { + if (typeof window !== 'undefined') { + const address = localStorage.getItem('address') + if (address) return JSON.parse(address) + } + return {} +} + +const setAddress = (address) => { + if (typeof window !== 'undefined') { + localStorage.setItem('address', JSON.stringify(address)) + } + return +} + +const getItemAddress = (key) => { + let address = getAddress() + return address[key] +} + +const updateItemAddress = (key, value) => { + let address = getAddress() + address[key] = value + setAddress(address) + return +} + +export { + getItemAddress, + updateItemAddress +} \ No newline at end of file -- cgit v1.2.3 From 036e72780ddb7a510795b329919ff9dd957af6d7 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Tue, 21 Feb 2023 22:38:25 +0700 Subject: fix --- src/core/components/elements/Sidebar/Sidebar.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/core') diff --git a/src/core/components/elements/Sidebar/Sidebar.jsx b/src/core/components/elements/Sidebar/Sidebar.jsx index c840a688..48ceacf6 100644 --- a/src/core/components/elements/Sidebar/Sidebar.jsx +++ b/src/core/components/elements/Sidebar/Sidebar.jsx @@ -1,8 +1,8 @@ import Link from "../Link/Link" import greeting from "@/core/utils/greeting" -import { Cog6ToothIcon } from "@heroicons/react/24/solid" import useAuth from "@/core/hooks/useAuth" import { AnimatePresence, motion } from "framer-motion" +import { CogIcon } from "@heroicons/react/24/outline" const Sidebar = ({ active, @@ -61,7 +61,7 @@ const Sidebar = ({ href="/my/menu" className="!text-gray_r-11 ml-auto my-auto" > - + ) } -- cgit v1.2.3 From 3c559031623649a67825ff47f34512f0eb946861 Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 22 Feb 2023 10:14:32 +0700 Subject: fix --- src/core/components/elements/Select/HookFormSelect.jsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/core/components/elements/Select/HookFormSelect.jsx (limited to 'src/core') diff --git a/src/core/components/elements/Select/HookFormSelect.jsx b/src/core/components/elements/Select/HookFormSelect.jsx new file mode 100644 index 00000000..45cd89b6 --- /dev/null +++ b/src/core/components/elements/Select/HookFormSelect.jsx @@ -0,0 +1,17 @@ +import ReactSelect from "react-select" + +const HookFormSelect = ({ + field, + ...props +}) => ( + field.onChange(option.value)} + value={field.value ? props.options.find(option => option.value === field.value) : ''} + isDisabled={props.disabled} + {...props} + /> +) + +export default HookFormSelect \ No newline at end of file -- cgit v1.2.3 From f66b12fd1d0b83af0d7230d7b1565fbe00afbe3c Mon Sep 17 00:00:00 2001 From: Rafi Zadanly Date: Wed, 22 Feb 2023 11:03:34 +0700 Subject: prettier --- src/core/api/odooApi.js | 12 ++- src/core/api/searchSuggestApi.js | 8 +- src/core/components/Seo.jsx | 6 +- src/core/components/elements/Alert/Alert.jsx | 2 +- src/core/components/elements/Appbar/Appbar.jsx | 34 ++++--- src/core/components/elements/Badge/Badge.jsx | 15 +-- src/core/components/elements/Divider/Divider.jsx | 8 +- src/core/components/elements/Image/Image.jsx | 12 +-- src/core/components/elements/Link/Link.jsx | 8 +- src/core/components/elements/Navbar/Navbar.jsx | 40 ++++---- src/core/components/elements/Navbar/Search.jsx | 56 ++++++----- .../components/elements/Pagination/Pagination.js | 102 ++++++++++++--------- src/core/components/elements/Popup/BottomPopup.jsx | 33 +++---- .../components/elements/Select/HookFormSelect.jsx | 13 +-- src/core/components/elements/Sidebar/Sidebar.jsx | 84 +++++++++-------- .../components/elements/Skeleton/BrandSkeleton.jsx | 8 +- .../components/elements/Skeleton/ImageSkeleton.jsx | 18 +++- .../elements/Skeleton/ProductCardSkeleton.jsx | 33 ++++--- src/core/components/elements/Spinner/Spinner.jsx | 26 ++++-- src/core/components/layouts/AnimationLayout.jsx | 28 +++--- src/core/components/layouts/AppLayout.jsx | 10 +- src/core/components/layouts/BasicLayout.jsx | 12 +-- src/core/hooks/useActive.js | 10 +- src/core/hooks/useAuth.js | 6 +- src/core/hooks/useSidebar.js | 8 +- src/core/utils/address.js | 5 +- src/core/utils/auth.js | 12 +-- src/core/utils/cart.js | 7 +- src/core/utils/currencyFormat.js | 4 +- src/core/utils/getFileBase64.js | 21 +++-- src/core/utils/greeting.js | 2 +- src/core/utils/slug.js | 18 ++-- src/core/utils/toTitleCase.js | 11 +-- 33 files changed, 347 insertions(+), 325 deletions(-) (limited to 'src/core') diff --git a/src/core/api/odooApi.js b/src/core/api/odooApi.js index 59d88faa..202c355e 100644 --- a/src/core/api/odooApi.js +++ b/src/core/api/odooApi.js @@ -25,13 +25,15 @@ const odooApi = async (method, url, data = {}, headers = {}) => { const auth = getAuth() let axiosParameter = { - method, + method, url: process.env.ODOO_HOST + url, - headers: {'Authorization': token, ...headers} + headers: { Authorization: token, ...headers } } if (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() + 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() let res = await axios(axiosParameter) if (res.data.status.code == 401 && connectionAttempt < maxConnectionAttempt) { @@ -44,4 +46,4 @@ const odooApi = async (method, url, data = {}, headers = {}) => { } } -export default odooApi; \ No newline at end of file +export default odooApi diff --git a/src/core/api/searchSuggestApi.js b/src/core/api/searchSuggestApi.js index b5edebda..e4445c9a 100644 --- a/src/core/api/searchSuggestApi.js +++ b/src/core/api/searchSuggestApi.js @@ -1,7 +1,9 @@ -import axios from "axios" +import axios from 'axios' const searchSuggestApi = async ({ query }) => { - const dataSearchSuggest = await axios(`${process.env.SELF_HOST}/api/shop/suggest?q=${query.trim()}`) + const dataSearchSuggest = await axios( + `${process.env.SELF_HOST}/api/shop/suggest?q=${query.trim()}` + ) return dataSearchSuggest } @@ -9,4 +11,4 @@ searchSuggestApi.defaultProps = { query: '' } -export default searchSuggestApi \ No newline at end of file +export default searchSuggestApi diff --git a/src/core/components/Seo.jsx b/src/core/components/Seo.jsx index bcfaa6ef..e688077e 100644 --- a/src/core/components/Seo.jsx +++ b/src/core/components/Seo.jsx @@ -1,11 +1,11 @@ -import Head from "next/head" +import Head from 'next/head' const Seo = ({ title }) => { return ( - { title } + {title} ) } -export default Seo \ No newline at end of file +export default Seo diff --git a/src/core/components/elements/Alert/Alert.jsx b/src/core/components/elements/Alert/Alert.jsx index 3f5584b9..695be8a3 100644 --- a/src/core/components/elements/Alert/Alert.jsx +++ b/src/core/components/elements/Alert/Alert.jsx @@ -18,4 +18,4 @@ const Alert = ({ children, className, type }) => { ) } -export default Alert \ No newline at end of file +export default Alert diff --git a/src/core/components/elements/Appbar/Appbar.jsx b/src/core/components/elements/Appbar/Appbar.jsx index 36df9edb..4300287f 100644 --- a/src/core/components/elements/Appbar/Appbar.jsx +++ b/src/core/components/elements/Appbar/Appbar.jsx @@ -1,33 +1,31 @@ -import { useRouter } from "next/router" -import Link from "../Link/Link" -import { HomeIcon, Bars3Icon, ShoppingCartIcon, ChevronLeftIcon } from "@heroicons/react/24/outline" +import { useRouter } from 'next/router' +import Link from '../Link/Link' +import { HomeIcon, Bars3Icon, ShoppingCartIcon, ChevronLeftIcon } from '@heroicons/react/24/outline' const AppBar = ({ title }) => { const router = useRouter() return ( - ) } -export default AppBar \ No newline at end of file +export default AppBar diff --git a/src/core/components/elements/Badge/Badge.jsx b/src/core/components/elements/Badge/Badge.jsx index 5d8ebd1c..5e22db1a 100644 --- a/src/core/components/elements/Badge/Badge.jsx +++ b/src/core/components/elements/Badge/Badge.jsx @@ -1,14 +1,7 @@ -const Badge = ({ - children, - type, - ...props -}) => { +const Badge = ({ children, type, ...props }) => { return ( -
- { children } +
+ {children}
) } @@ -30,4 +23,4 @@ const badgeStyle = (type) => { return className.join(' ') } -export default Badge \ No newline at end of file +export default Badge diff --git a/src/core/components/elements/Divider/Divider.jsx b/src/core/components/elements/Divider/Divider.jsx index 355cd509..ce54a2ea 100644 --- a/src/core/components/elements/Divider/Divider.jsx +++ b/src/core/components/elements/Divider/Divider.jsx @@ -1,11 +1,7 @@ -const Divider = (props) => { - return ( -
- ) -} +const Divider = (props) =>
Divider.defaultProps = { className: '' } -export default Divider \ No newline at end of file +export default Divider diff --git a/src/core/components/elements/Image/Image.jsx b/src/core/components/elements/Image/Image.jsx index a6f0b00c..ac82aaaf 100644 --- a/src/core/components/elements/Image/Image.jsx +++ b/src/core/components/elements/Image/Image.jsx @@ -1,18 +1,18 @@ -import { LazyLoadImage } from "react-lazy-load-image-component" -import "react-lazy-load-image-component/src/effects/opacity.css" +import { LazyLoadImage } from 'react-lazy-load-image-component' +import 'react-lazy-load-image-component/src/effects/opacity.css' const Image = ({ ...props }) => ( <> ) Image.defaultProps = LazyLoadImage.defaultProps -export default Image \ No newline at end of file +export default Image diff --git a/src/core/components/elements/Link/Link.jsx b/src/core/components/elements/Link/Link.jsx index 897cf6d7..dbc65338 100644 --- a/src/core/components/elements/Link/Link.jsx +++ b/src/core/components/elements/Link/Link.jsx @@ -1,9 +1,9 @@ -import NextLink from "next/link" +import NextLink from 'next/link' const Link = ({ children, ...props }) => { return ( - @@ -14,4 +14,4 @@ const Link = ({ children, ...props }) => { Link.defaultProps = NextLink.defaultProps -export default Link \ No newline at end of file +export default Link diff --git a/src/core/components/elements/Navbar/Navbar.jsx b/src/core/components/elements/Navbar/Navbar.jsx index f10ebd63..e2caebfe 100644 --- a/src/core/components/elements/Navbar/Navbar.jsx +++ b/src/core/components/elements/Navbar/Navbar.jsx @@ -1,38 +1,38 @@ -import dynamic from "next/dynamic" -import Image from "next/image" -import IndoteknikLogo from "@/images/logo.png" -import { Bars3Icon, HeartIcon, ShoppingCartIcon } from "@heroicons/react/24/outline" -import Link from "../Link/Link" -import useSidebar from "@/core/hooks/useSidebar" +import dynamic from 'next/dynamic' +import Image from 'next/image' +import IndoteknikLogo from '@/images/logo.png' +import { Bars3Icon, HeartIcon, ShoppingCartIcon } from '@heroicons/react/24/outline' +import Link from '../Link/Link' +import useSidebar from '@/core/hooks/useSidebar' -const Search = dynamic(() => import("./Search")) +const Search = dynamic(() => import('./Search')) const Navbar = () => { const { Sidebar, open } = useSidebar() return ( <> -