summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorHATEC\SPVDEV001 <tri.susilo@altama.co.id>2023-04-11 11:06:38 +0700
committerHATEC\SPVDEV001 <tri.susilo@altama.co.id>2023-04-11 11:06:38 +0700
commit3df233e0c23e7d4503931ab6ec8ffc41642ac104 (patch)
treeccc032defe422f5fafc4a08af672833b2fe41835 /src/core
parent006c77a85786c24199db157d1d70f48b47311d35 (diff)
parentf0a720441def88187b3913268238c379362fb9d3 (diff)
Merge branch 'master' into development_tri/feedback_UAT
Diffstat (limited to 'src/core')
-rw-r--r--src/core/api/odooApi.js11
-rw-r--r--src/core/components/elements/Alert/Alert.jsx10
-rw-r--r--src/core/components/elements/Appbar/Appbar.jsx29
-rw-r--r--src/core/components/elements/Divider/Divider.jsx8
-rw-r--r--src/core/components/elements/Image/Image.jsx8
-rw-r--r--src/core/components/elements/Link/Link.jsx16
-rw-r--r--src/core/components/elements/Navbar/NavbarMobile.jsx12
-rw-r--r--src/core/components/elements/Navbar/Search.jsx10
-rw-r--r--src/core/components/elements/Pagination/Pagination.js5
-rw-r--r--src/core/components/elements/Popup/BottomPopup.jsx6
-rw-r--r--src/core/components/elements/Skeleton/BrandSkeleton.jsx5
-rw-r--r--src/core/components/elements/Skeleton/ImageSkeleton.jsx10
-rw-r--r--src/core/components/elements/Skeleton/ProductCardSkeleton.jsx5
-rw-r--r--src/core/components/elements/Spinner/LogoSpinner.jsx15
-rw-r--r--src/core/hooks/useDevice.js1
-rw-r--r--src/core/hooks/useSidebar.js7
-rw-r--r--src/core/utils/address.js35
-rw-r--r--src/core/utils/auth.js20
-rw-r--r--src/core/utils/cart.js41
-rw-r--r--src/core/utils/currencyFormat.js6
-rw-r--r--src/core/utils/getFileBase64.js13
-rw-r--r--src/core/utils/greeting.js10
-rw-r--r--src/core/utils/slug.js24
-rw-r--r--src/core/utils/toTitleCase.js9
24 files changed, 230 insertions, 86 deletions
diff --git a/src/core/api/odooApi.js b/src/core/api/odooApi.js
index 25ee9adf..fe9fcdd2 100644
--- a/src/core/api/odooApi.js
+++ b/src/core/api/odooApi.js
@@ -18,6 +18,17 @@ const getToken = async () => {
const maxConnectionAttempt = 15
let connectionAttempt = 0
+/**
+ * The `odooApi` function is used to make API requests to an Odoo backend with customizable parameters such as `method`, `url`, `data`, and `headers`.
+ *
+ * @async
+ * @function
+ * @param {string} method - HTTP method for the API request (e.g., GET, POST, PUT, DELETE).
+ * @param {string} url - URL endpoint for the API request.
+ * @param {Object} data - Data to be sent in the request payload.
+ * @param {Object} headers - Custom headers to be sent in the request.
+ * @returns {Promise} - A Promise that resolves to the API response data or an empty array.
+ */
const odooApi = async (method, url, data = {}, headers = {}) => {
connectionAttempt++
try {
diff --git a/src/core/components/elements/Alert/Alert.jsx b/src/core/components/elements/Alert/Alert.jsx
index 695be8a3..cf84b591 100644
--- a/src/core/components/elements/Alert/Alert.jsx
+++ b/src/core/components/elements/Alert/Alert.jsx
@@ -1,3 +1,13 @@
+/**
+ * The Alert component is used to display different types of alerts or notifications
+ * with different styles based on the provided type prop.
+ *
+ * @param {Object} props - Props received by the component.
+ * @param {ReactNode} props.children - The content to be displayed inside the alert.
+ * @param {string} props.className - Additional CSS class names for the alert.
+ * @param {string} props.type - The type of the alert ('info', 'success', or 'warning').
+ * @returns {JSX.Element} - Rendered Alert component.
+ */
const Alert = ({ children, className, type }) => {
let typeClass = ''
switch (type) {
diff --git a/src/core/components/elements/Appbar/Appbar.jsx b/src/core/components/elements/Appbar/Appbar.jsx
index 098d0a33..f1456a7c 100644
--- a/src/core/components/elements/Appbar/Appbar.jsx
+++ b/src/core/components/elements/Appbar/Appbar.jsx
@@ -2,38 +2,33 @@ import { useRouter } from 'next/router'
import Link from '../Link/Link'
import { HomeIcon, Bars3Icon, ShoppingCartIcon, ChevronLeftIcon } from '@heroicons/react/24/outline'
+/**
+ * The AppBar component is a navigation component used to display a header or toolbar
+ * in a web application.
+ *
+ * @param {Object} props - Props received by the component.
+ * @param {string} props.title - The title to be displayed on the AppBar.
+ * @returns {JSX.Element} - Rendered AppBar component.
+ */
const AppBar = ({ title }) => {
const router = useRouter()
return (
<nav className='sticky top-0 z-50 bg-white border-b border-gray_r-6 flex justify-between'>
<div className='flex items-center'>
- <button
- type='button'
- className='p-4'
- onClick={() => router.back()}
- >
+ <button type='button' className='p-4' onClick={() => router.back()}>
<ChevronLeftIcon className='w-6 stroke-2' />
</button>
<div className='font-medium text-h-sm line-clamp-1'>{title}</div>
</div>
<div className='flex items-center px-2'>
- <Link
- href='/shop/cart'
- className='py-4 px-2'
- >
+ <Link href='/shop/cart' className='py-4 px-2'>
<ShoppingCartIcon className='w-6 text-gray_r-12' />
</Link>
- <Link
- href='/'
- className='py-4 px-2'
- >
+ <Link href='/' className='py-4 px-2'>
<HomeIcon className='w-6 text-gray_r-12' />
</Link>
- <Link
- href='/my/menu'
- className='py-4 px-2'
- >
+ <Link href='/my/menu' className='py-4 px-2'>
<Bars3Icon className='w-6 text-gray_r-12' />
</Link>
</div>
diff --git a/src/core/components/elements/Divider/Divider.jsx b/src/core/components/elements/Divider/Divider.jsx
index ce54a2ea..f3650b00 100644
--- a/src/core/components/elements/Divider/Divider.jsx
+++ b/src/core/components/elements/Divider/Divider.jsx
@@ -1,3 +1,11 @@
+/**
+ * The Divider component is used to create a horizontal line or divider with a specific
+ * background color based on the provided className prop.
+ *
+ * @param {Object} props - Props that are passed to the Divider component.
+ * @param {string} props.className - Additional CSS classes to apply to the divider.
+ * @returns {JSX.Element} - Rendered Divider component.
+ */
const Divider = (props) => <div className={`h-1 bg-gray_r-4 ${props.className}`} />
Divider.defaultProps = {
diff --git a/src/core/components/elements/Image/Image.jsx b/src/core/components/elements/Image/Image.jsx
index ac82aaaf..ba6bf50d 100644
--- a/src/core/components/elements/Image/Image.jsx
+++ b/src/core/components/elements/Image/Image.jsx
@@ -1,6 +1,14 @@
import { LazyLoadImage } from 'react-lazy-load-image-component'
import 'react-lazy-load-image-component/src/effects/opacity.css'
+/**
+ * The `Image` component is used to display lazy-loaded images.
+ *
+ * @param {Object} props - Props passed to the `Image` component.
+ * @param {string} props.src - URL of the image to be displayed.
+ * @param {string} props.alt - Alternative text to be displayed if the image is not found.
+ * @returns {JSX.Element} - Rendered `Image` component.
+ */
const Image = ({ ...props }) => (
<>
<LazyLoadImage
diff --git a/src/core/components/elements/Link/Link.jsx b/src/core/components/elements/Link/Link.jsx
index 360444a6..f6b39d45 100644
--- a/src/core/components/elements/Link/Link.jsx
+++ b/src/core/components/elements/Link/Link.jsx
@@ -1,14 +1,14 @@
import NextLink from 'next/link'
-import { useRouter } from 'next/router'
-import { useEffect } from 'react'
+/**
+ * The `Link` component is used to render Next.js links with customizable properties such as `children`, `scroll`, and `className`.
+ *
+ * @param {Object} props - Props passed to the `Link` component.
+ * @param {ReactNode} props.children - Child elements to be rendered as link content.
+ * @param {string} props.className - Additional CSS class to be applied to the link.
+ * @returns {JSX.Element} - Rendered `Link` component.
+ */
const Link = ({ children, ...props }) => {
- const router = useRouter()
-
- useEffect(() => {
- router.events.on('routeChangeComplete', () => window.scrollTo({ top: 0, behavior: 'smooth' }))
- }, [router])
-
return (
<NextLink
{...props}
diff --git a/src/core/components/elements/Navbar/NavbarMobile.jsx b/src/core/components/elements/Navbar/NavbarMobile.jsx
index 3998875b..24ff3a51 100644
--- a/src/core/components/elements/Navbar/NavbarMobile.jsx
+++ b/src/core/components/elements/Navbar/NavbarMobile.jsx
@@ -16,12 +16,7 @@ const NavbarMobile = () => {
<nav className='px-4 py-2 pb-3 sticky top-0 z-50 bg-white shadow'>
<div className='flex justify-between items-center mb-2'>
<Link href='/'>
- <Image
- src={IndoteknikLogo}
- alt='Indoteknik Logo'
- width={120}
- height={40}
- />
+ <Image src={IndoteknikLogo} alt='Indoteknik Logo' width={120} height={40} />
</Link>
<div className='flex gap-x-3'>
<Link href='/my/wishlist'>
@@ -30,10 +25,7 @@ const NavbarMobile = () => {
<Link href='/shop/cart'>
<ShoppingCartIcon className='w-6 text-gray_r-12' />
</Link>
- <button
- type='button'
- onClick={open}
- >
+ <button type='button' onClick={open}>
<Bars3Icon className='w-6 text-gray_r-12' />
</button>
</div>
diff --git a/src/core/components/elements/Navbar/Search.jsx b/src/core/components/elements/Navbar/Search.jsx
index d0627b24..3046782b 100644
--- a/src/core/components/elements/Navbar/Search.jsx
+++ b/src/core/components/elements/Navbar/Search.jsx
@@ -45,10 +45,7 @@ const Search = () => {
return (
<>
- <form
- onSubmit={handleSubmit}
- className='flex-1 flex relative'
- >
+ <form onSubmit={handleSubmit} className='flex-1 flex relative'>
<input
type='text'
ref={queryRef}
@@ -59,10 +56,7 @@ const Search = () => {
onBlur={onInputBlur}
onFocus={loadSuggestion}
/>
- <button
- type='submit'
- className='rounded-r border border-l-0 border-gray_r-6 px-2'
- >
+ <button type='submit' className='rounded-r border border-l-0 border-gray_r-6 px-2'>
<MagnifyingGlassIcon className='w-6' />
</button>
diff --git a/src/core/components/elements/Pagination/Pagination.js b/src/core/components/elements/Pagination/Pagination.js
index 18964fc4..c009171f 100644
--- a/src/core/components/elements/Pagination/Pagination.js
+++ b/src/core/components/elements/Pagination/Pagination.js
@@ -26,10 +26,7 @@ const Pagination = ({ pageCount, currentPage, url, className }) => {
</Link>
)
let DotsComponent = (
- <div
- key={i}
- className='pagination-dots'
- >
+ <div key={i} className='pagination-dots'>
...
</div>
)
diff --git a/src/core/components/elements/Popup/BottomPopup.jsx b/src/core/components/elements/Popup/BottomPopup.jsx
index 1d65c7a3..80afa8d9 100644
--- a/src/core/components/elements/Popup/BottomPopup.jsx
+++ b/src/core/components/elements/Popup/BottomPopup.jsx
@@ -7,7 +7,7 @@ import ReactDOM from 'react-dom'
const transition = { ease: 'linear', duration: 0.2 }
-const BottomPopup = ({ children, active = false, title, close }) => {
+const BottomPopup = ({ children, active = false, title, close, className = '' }) => {
useEffect(() => {
if (active) {
document.querySelector('html, body').classList.add('overflow-hidden')
@@ -35,7 +35,7 @@ const BottomPopup = ({ children, active = false, title, close }) => {
animate={{ bottom: 0 }}
exit={{ bottom: '-100%' }}
transition={transition}
- className='fixed left-0 w-full border-t border-gray_r-6 rounded-t-xl z-[60] p-4 pt-0 bg-white max-h-[80vh] overflow-auto'
+ className={`fixed left-0 w-full border-t border-gray_r-6 rounded-t-xl z-[60] p-4 pt-0 bg-white max-h-[80vh] overflow-auto ${className}`}
>
<div className='flex justify-between py-4'>
<div className='font-semibold text-h-sm'>{title}</div>
@@ -53,7 +53,7 @@ const BottomPopup = ({ children, active = false, title, close }) => {
animate={{ bottom: '50%', opacity: 1 }}
exit={{ bottom: '45%', opacity: 0 }}
transition={transition}
- className='fixed left-1/2 -translate-x-1/2 translate-y-1/2 md:w-1/4 lg:w-1/3 border border-gray_r-6 rounded-xl z-[60] p-4 pt-0 bg-white max-h-[80vh] overflow-auto'
+ className={`fixed left-1/2 -translate-x-1/2 translate-y-1/2 md:w-1/4 lg:w-1/3 border border-gray_r-6 rounded-xl z-[60] p-4 pt-0 bg-white max-h-[80vh] overflow-auto ${className}`}
>
<div className='flex justify-between py-4'>
<div className='font-semibold text-h-sm'>{title}</div>
diff --git a/src/core/components/elements/Skeleton/BrandSkeleton.jsx b/src/core/components/elements/Skeleton/BrandSkeleton.jsx
index 9a34fb9b..9a7a51f9 100644
--- a/src/core/components/elements/Skeleton/BrandSkeleton.jsx
+++ b/src/core/components/elements/Skeleton/BrandSkeleton.jsx
@@ -1,8 +1,5 @@
const BrandSkeleton = () => (
- <div
- role='status'
- className='animate-pulse'
- >
+ <div role='status' className='animate-pulse'>
<div className='h-12 bg-gray-200 rounded'></div>
<span className='sr-only'>Loading...</span>
</div>
diff --git a/src/core/components/elements/Skeleton/ImageSkeleton.jsx b/src/core/components/elements/Skeleton/ImageSkeleton.jsx
index 39d06331..2ca6b2a3 100644
--- a/src/core/components/elements/Skeleton/ImageSkeleton.jsx
+++ b/src/core/components/elements/Skeleton/ImageSkeleton.jsx
@@ -1,12 +1,6 @@
const ImageSkeleton = () => (
- <div
- role='status'
- className='animate-pulse'
- >
- <div
- className='flex items-center justify-center h-56 mb-4 bg-gray-300 rounded'
- aria-busy
- >
+ <div role='status' className='animate-pulse'>
+ <div className='flex items-center justify-center h-56 mb-4 bg-gray-300 rounded' aria-busy>
<svg
className='w-12 h-12 text-gray-200'
xmlns='http://www.w3.org/2000/svg'
diff --git a/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx b/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx
index ddc0d3bc..84d1c0d1 100644
--- a/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx
+++ b/src/core/components/elements/Skeleton/ProductCardSkeleton.jsx
@@ -3,10 +3,7 @@ const ProductCardSkeleton = () => (
role='status'
className='p-4 max-w-sm rounded border border-gray-300 shadow animate-pulse md:p-6'
>
- <div
- className='flex items-center justify-center h-36 mb-4 bg-gray-300 rounded'
- aria-busy
- >
+ <div className='flex items-center justify-center h-36 mb-4 bg-gray-300 rounded' aria-busy>
<svg
className='w-12 h-12 text-gray-200'
xmlns='http://www.w3.org/2000/svg'
diff --git a/src/core/components/elements/Spinner/LogoSpinner.jsx b/src/core/components/elements/Spinner/LogoSpinner.jsx
new file mode 100644
index 00000000..73b84e84
--- /dev/null
+++ b/src/core/components/elements/Spinner/LogoSpinner.jsx
@@ -0,0 +1,15 @@
+import Image from 'next/image'
+import IndoteknikLogo from '@/images/LOGO-INDOTEKNIK-GEAR.png'
+
+const LogoSpinner = ({ ...props }) => (
+ <Image
+ src={IndoteknikLogo}
+ alt='Indoteknik Logo'
+ width={64}
+ height={64}
+ className='page-loader'
+ {...props}
+ />
+)
+
+export default LogoSpinner
diff --git a/src/core/hooks/useDevice.js b/src/core/hooks/useDevice.js
index a8584692..7ecf5a31 100644
--- a/src/core/hooks/useDevice.js
+++ b/src/core/hooks/useDevice.js
@@ -22,7 +22,6 @@ const useDevice = () => {
}
}, [])
-
return {
isMobile,
isDesktop
diff --git a/src/core/hooks/useSidebar.js b/src/core/hooks/useSidebar.js
index 4da61ac2..c463fd81 100644
--- a/src/core/hooks/useSidebar.js
+++ b/src/core/hooks/useSidebar.js
@@ -15,12 +15,7 @@ const useSidebar = () => {
return {
open: activate,
- Sidebar: (
- <SidebarComponent
- active={active}
- close={deactivate}
- />
- )
+ Sidebar: <SidebarComponent active={active} close={deactivate} />
}
}
diff --git a/src/core/utils/address.js b/src/core/utils/address.js
index c545d34b..b20feba3 100644
--- a/src/core/utils/address.js
+++ b/src/core/utils/address.js
@@ -1,28 +1,53 @@
+/**
+ * Gets the address data from local storage.
+ *
+ * @returns {object} - Returns the address data as an object, or an empty object if not found.
+ */
const getAddress = () => {
- if (typeof window !== 'undefined') {
+ if (typeof window !== 'undefined' && window.localStorage) {
const address = localStorage.getItem('address')
if (address) return JSON.parse(address)
}
return {}
}
+/**
+ * Sets the address data to local storage.
+ *
+ * @param {object} address - The address data to be stored as an object.
+ * @returns {boolean} - Returns `true` if the address data is successfully stored, `false` otherwise.
+ */
const setAddress = (address) => {
- if (typeof window !== 'undefined') {
+ if (typeof window !== 'undefined' && window.localStorage) {
localStorage.setItem('address', JSON.stringify(address))
+ return true
}
- return
+ return false
}
+/**
+ * Gets the value of a specific key from the address data.
+ *
+ * @param {string} key - The key of the address data to be retrieved.
+ * @returns {*} - The value of the specified key, or false if the key does not exist.
+ */
const getItemAddress = (key) => {
let address = getAddress()
- return address[key]
+ return address[key] || false
}
+/**
+ * Updates the value of a specific key in the address data.
+ *
+ * @param {string} key - The key of the address data to be updated.
+ * @param {*} value - The new value to be set for the specified key.
+ * @returns {boolean} - Returns `true`
+ */
const updateItemAddress = (key, value) => {
let address = getAddress()
address[key] = value
setAddress(address)
- return
+ return true
}
export { getItemAddress, updateItemAddress }
diff --git a/src/core/utils/auth.js b/src/core/utils/auth.js
index 13e0e79d..cddff2b8 100644
--- a/src/core/utils/auth.js
+++ b/src/core/utils/auth.js
@@ -1,18 +1,32 @@
import { deleteCookie, getCookie, setCookie } from 'cookies-next'
+/**
+ * Retrieves authentication data from cookie and returns it as an object.
+ *
+ * @returns {Object|boolean} - Returns the authentication data as an object if available in cookie, otherwise `false`.
+ */
const getAuth = () => {
let auth = getCookie('auth')
- if (auth) {
- return JSON.parse(auth)
- }
+ if (auth) return JSON.parse(auth)
return false
}
+/**
+ * Sets the authentication data in cookie with the given user data.
+ *
+ * @param {Object} user - The user data to be set as authentication data in cookie.
+ * @returns {boolean} - Returns `true`.
+ */
const setAuth = (user) => {
setCookie('auth', JSON.stringify(user))
return true
}
+/**
+ * Deletes the authentication data stored in cookie.
+ *
+ * @returns {boolean} - Returns `true`.
+ */
const deleteAuth = () => {
deleteCookie('auth')
return true
diff --git a/src/core/utils/cart.js b/src/core/utils/cart.js
index fd42ee4e..2bdffb1c 100644
--- a/src/core/utils/cart.js
+++ b/src/core/utils/cart.js
@@ -1,23 +1,51 @@
+/**
+ * Retrieves cart data from localStorage, if available.
+ *
+ * @returns {Object} - The cart data as an object, or an empty object if not found.
+ */
const getCart = () => {
- if (typeof window !== 'undefined') {
+ if (typeof window !== 'undefined' && window.localStorage) {
const cart = localStorage.getItem('cart')
if (cart) return JSON.parse(cart)
}
return {}
}
+/**
+ * Saves cart data to localStorage, if available.
+ *
+ * @param {Object} cart - The cart data to be saved.
+ * @returns {boolean} - Returns `true` if cart data is saved successfully, `false` otherwise.
+ */
const setCart = (cart) => {
- if (typeof window !== 'undefined') {
+ if (typeof window !== 'undefined' && window.localStorage) {
localStorage.setItem('cart', JSON.stringify(cart))
+ return true
}
- return true
+ return false
}
+/**
+ * Retrieves an item from the cart data based on the given product ID.
+ *
+ * @param {Object} options - The options object containing the productId.
+ * @param {string} options.productId - The ID of the product to be retrieved from the cart.
+ * @returns {Object} - Returns the item object from the cart data, or `undefined` if not found.
+ */
const getItemCart = ({ productId }) => {
let cart = getCart()
return cart[productId]
}
+/**
+ * Updates an item in the cart data with the given productId, quantity, and selected status.
+ *
+ * @param {Object} options - The options object containing the productId, quantity, and selected status.
+ * @param {string} options.productId - The ID of the product to be updated in the cart.
+ * @param {number} options.quantity - The new quantity of the product in the cart.
+ * @param {boolean} [options.selected=false] - The new selected status of the product in the cart. Default is `false`.
+ * @returns {boolean} - Returns `true`.
+ */
const updateItemCart = ({ productId, quantity, selected = false }) => {
let cart = getCart()
quantity = parseInt(quantity)
@@ -26,6 +54,13 @@ const updateItemCart = ({ productId, quantity, selected = false }) => {
return true
}
+/**
+ * Deletes an item from the cart data with the given productId.
+ *
+ * @param {Object} options - The options object containing the productId.
+ * @param {string} options.productId - The ID of the product to be deleted from the cart.
+ * @returns {boolean} - Returns `true`.
+ */
const deleteItemCart = ({ productId }) => {
let cart = getCart()
delete cart[productId]
diff --git a/src/core/utils/currencyFormat.js b/src/core/utils/currencyFormat.js
index 12b68111..d0eba4c4 100644
--- a/src/core/utils/currencyFormat.js
+++ b/src/core/utils/currencyFormat.js
@@ -1,3 +1,9 @@
+/**
+ * Formats a numeric value as a currency string in Indonesian Rupiah (IDR) format.
+ *
+ * @param {number} value - The numeric value to be formatted as currency.
+ * @returns {string} - The currency string in IDR format.
+ */
const currencyFormat = (value) => {
const currency = new Intl.NumberFormat('id-ID', {
style: 'currency',
diff --git a/src/core/utils/getFileBase64.js b/src/core/utils/getFileBase64.js
index 4fa7316b..ed6ae000 100644
--- a/src/core/utils/getFileBase64.js
+++ b/src/core/utils/getFileBase64.js
@@ -1,5 +1,13 @@
-const getFileBase64 = (file) =>
- new Promise((resolve, reject) => {
+/**
+ * Converts a File object to base64 string using FileReader.
+ *
+ * @param {File} file - The File object to be converted.
+ * @returns {Promise<string>} - A Promise that resolves with the base64 string
+ * representing the contents of the File, or rejects with an error if there's
+ * any issue with the file reading process.
+ */
+const getFileBase64 = (file) => {
+ return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.readAsBinaryString(file)
reader.onload = () => {
@@ -8,5 +16,6 @@ const getFileBase64 = (file) =>
}
reader.onerror = (error) => reject(error)
})
+}
export default getFileBase64
diff --git a/src/core/utils/greeting.js b/src/core/utils/greeting.js
index aaaade7a..d349033e 100644
--- a/src/core/utils/greeting.js
+++ b/src/core/utils/greeting.js
@@ -1,3 +1,13 @@
+/**
+ * Generates a greeting based on the current time of day.
+ * The greeting is determined by the hour of the day:
+ * - "Selamat Pagi" for hours before 11:00
+ * - "Selamat Siang" for hours between 11:00 and 15:00
+ * - "Selamat Sore" for hours between 15:00 and 18:00
+ * - "Selamat Malam" for hours after 18:00
+ *
+ * @returns {string} - The generated greeting message.
+ */
const greeting = () => {
let hours = new Date().getHours()
if (hours < 11) return 'Selamat Pagi'
diff --git a/src/core/utils/slug.js b/src/core/utils/slug.js
index 7010008a..d5eecd3e 100644
--- a/src/core/utils/slug.js
+++ b/src/core/utils/slug.js
@@ -1,5 +1,14 @@
import toTitleCase from './toTitleCase'
+/**
+ * Creates a slug from input parameters by converting the name and appending it with an ID.
+ * The slug is generated by removing special characters, converting to lowercase, and joining with hyphens.
+ *
+ * @param {string} prefix - The prefix to be added to the generated slug.
+ * @param {string} name - The name used to generate the slug.
+ * @param {number} id - The ID to be appended to the slug.
+ * @returns {string} - The generated slug with the prefix, name, and ID.
+ */
const createSlug = (prefix, name, id) => {
let slug =
name
@@ -13,11 +22,26 @@ const createSlug = (prefix, name, id) => {
return prefix + filterSlugFromEmptyChar.join('-')
}
+/**
+ * Extracts the ID from a slug.
+ * The ID is retrieved from the last segment of the slug, separated by hyphens.
+ *
+ * @param {string} slug - The slug from which to extract the ID.
+ * @returns {string} - The extracted ID from the slug.
+ */
const getIdFromSlug = (slug) => {
let id = slug.split('-')
return id[id.length - 1]
}
+/**
+ * Extracts the name from a slug.
+ * The name is retrieved from all segments of the slug, except for the last one, separated by hyphens.
+ * The retrieved name is then converted to title case.
+ *
+ * @param {string} slug - The slug from which to extract the name.
+ * @returns {string} - The extracted name from the slug in title case.
+ */
const getNameFromSlug = (slug) => {
let name = slug.split('-')
name.pop()
diff --git a/src/core/utils/toTitleCase.js b/src/core/utils/toTitleCase.js
index 4335824d..dab1dc33 100644
--- a/src/core/utils/toTitleCase.js
+++ b/src/core/utils/toTitleCase.js
@@ -1,3 +1,12 @@
+/**
+ * Converts a string to title case.
+ * Title case capitalizes the first character of each word in the string,
+ * and sets the remaining characters to lowercase.
+ *
+ * @param {string} str - The input string to be converted to title case.
+ * @returns {string} - The string in title case.
+ */
+
const toTitleCase = (str) => {
return str.replace(/\w\S*/g, function (txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()