diff options
| author | Rafi Zadanly <zadanlyr@gmail.com> | 2023-10-23 17:11:33 +0700 |
|---|---|---|
| committer | Rafi Zadanly <zadanlyr@gmail.com> | 2023-10-23 17:11:33 +0700 |
| commit | 90710579ba1c12060877f6ec2d26103f9c31058d (patch) | |
| tree | 307032cfb8cd13b790c569bc443258b00b07684e | |
| parent | a001da95b9c03167656aec8a573cf60c12164b3f (diff) | |
Refactor and migrate register page
78 files changed, 1670 insertions, 38 deletions
diff --git a/.prettierrc b/.prettierrc index 13d05134..c09debf4 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,11 +1,10 @@ { + "arrowParens": "always", + "singleQuote": true, + "jsxSingleQuote": true, "tabWidth": 2, + "semi": true, "useTabs": false, - "semi": false, - "jsxSingleQuote": true, - "singleQuote": true, - "printWidth": 100, - "trailingComma": "none", "overrides": [ { "files": "*.css", diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index 29f6bcc5..00000000 --- a/jsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": "./src/", - "paths": { - "@/*": ["./*"] - } - } -}
\ No newline at end of file diff --git a/package.json b/package.json index cabe4ed4..127de3df 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "axios": "^1.1.3", "camelcase-object-deep": "^1.1.7", "classnames": "^2.3.2", + "clsx": "^2.0.0", "cookies-next": "^2.1.1", "flowbite": "^1.6.4", "framer-motion": "^7.10.3", @@ -46,16 +47,23 @@ "react-query": "^3.39.3", "react-select": "^5.7.0", "swiper": "^8.4.4", + "tw-merge": "^0.0.1-alpha.3", + "usehooks-ts": "^2.9.1", "xmlbuilder": "^15.1.1", - "yup": "^0.32.11" + "yup": "^0.32.11", + "zustand": "^4.4.4" }, "devDependencies": { "@svgr/webpack": "^6.5.0", "@tailwindcss/typography": "^0.5.9", + "@types/node": "^20.8.7", + "@types/react": "^18.2.31", + "@types/react-dom": "^18.2.14", "autoprefixer": "^10.4.14", "eslint": "8.26.0", "eslint-config-next": "13.0.0", "postcss": "^8.4.21", - "tailwindcss": "^3.2.7" + "tailwindcss": "^3.2.7", + "typescript": "^5.2.2" } } diff --git a/src-migrate/common/components/elements/Modal.tsx b/src-migrate/common/components/elements/Modal.tsx new file mode 100644 index 00000000..ad1fe51b --- /dev/null +++ b/src-migrate/common/components/elements/Modal.tsx @@ -0,0 +1,84 @@ +import { XMarkIcon } from "@heroicons/react/24/outline"; +import { AnimatePresence, motion } from "framer-motion" +import { useEffect, useState } from "react"; +import ReactDOM from "react-dom"; +import { useWindowSize } from "usehooks-ts"; +import clsxm from "~/common/libs/clsxm"; + + +type Props = { + children: React.ReactNode + active: boolean + title?: string + close?: () => void, + className?: string +} + +const Modal = ({ + children, + active = false, + title, + close, + className +}: Props) => { + const { width } = useWindowSize() + const [rendered, setRendered] = useState<boolean>(false) + + useEffect(() => { + setRendered(true) + }, []) + + const modalClassNames = clsxm( + "fixed bg-white max-h-[80vh] overflow-auto p-4 pt-0 z-[60] border-gray_r-6", + { + "left-1/2 -translate-x-1/2 translate-y-1/2 bottom-1/2 md:w-1/4 lg:w-1/3 border rounded-xl": width >= 768, + "left-0 w-full border-t bottom-0 rounded-t-xl": width < 768 + }, + className + ) + + const variant = { + initial: { bottom: width >= 768 ? '45%' : '-100%', opacity: 0 }, + animate: { bottom: width >= 768 ? '50%' : 0, opacity: 1 }, + exit: { bottom: width >= 768 ? '55%' : '-100%', opacity: 0 }, + transition: { ease: 'linear', duration: 0.25 } + } + + return rendered && ReactDOM.createPortal( + <AnimatePresence> + {active && ( + <motion.div + className="overlay" + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + exit={{ opacity: 0 }} + onClick={close} + /> + )} + + {active && ( + <motion.div + {...variant} + className={modalClassNames} + > + <div className='flex justify-between py-5 sticky top-0 bg-white'> + <div className='font-semibold text-h-sm md:text-title-sm'> + {title} + </div> + {close && ( + <button type='button' onClick={close}> + <XMarkIcon className='w-5 stroke-2' /> + </button> + )} + </div> + + {children} + </motion.div> + )} + + </AnimatePresence>, + document.querySelector('body')! + ) +} + +export default Modal
\ No newline at end of file diff --git a/src-migrate/common/components/skeleton/PageContentSkeleton.tsx b/src-migrate/common/components/skeleton/PageContentSkeleton.tsx new file mode 100644 index 00000000..bf85cff1 --- /dev/null +++ b/src-migrate/common/components/skeleton/PageContentSkeleton.tsx @@ -0,0 +1,19 @@ +const PageContentSkeleton = () => { + return ( + <div className="animate-pulse grid gap-y-4"> + <div className="w-full h-10 bg-gray-300 rounded" /> + <div className="h-2" /> + <div className="w-full h-4 bg-gray-300 rounded" /> + <div className="w-full h-4 bg-gray-300 rounded" /> + <div className="w-full h-4 bg-gray-300 rounded" /> + <div className="w-8/12 h-4 bg-gray-300 rounded" /> + <div className="h-2" /> + <div className="w-full h-4 bg-gray-300 rounded" /> + <div className="w-full h-4 bg-gray-300 rounded" /> + <div className="w-full h-4 bg-gray-300 rounded" /> + <div className="w-1/2 h-4 bg-gray-300 rounded" /> + </div> + ) +} + +export default PageContentSkeleton
\ No newline at end of file diff --git a/src-migrate/common/constants/menu.ts b/src-migrate/common/constants/menu.ts new file mode 100644 index 00000000..853da507 --- /dev/null +++ b/src-migrate/common/constants/menu.ts @@ -0,0 +1,20 @@ +import { SecondaryNavItemProps } from '../types/nav' + +export const SECONDARY_MENU_ITEMS: SecondaryNavItemProps[] = [ + { + label: 'Semua Brand', + href: '/shop/brands' + }, + { + label: 'Ready Stock', + href: '/shop/search?orderBy=stock' + }, + { + label: 'Blog Indoteknik', + href: 'https://blog.indoteknik.com/' + }, + { + label: 'Indoteknik TV', + href: '/video' + } +] diff --git a/src-migrate/common/libs/auth.ts b/src-migrate/common/libs/auth.ts new file mode 100644 index 00000000..fb4e836a --- /dev/null +++ b/src-migrate/common/libs/auth.ts @@ -0,0 +1,26 @@ +import { deleteCookie, getCookie, setCookie } from 'cookies-next'; +import { AuthProps } from '../types/auth'; + +const COOKIE_KEY = 'auth'; + +export const getAuth = (): AuthProps | boolean => { + const auth = getCookie(COOKIE_KEY); + + if (typeof auth === 'string') { + return JSON.parse(auth); + } + + return false; +}; + +export const setAuth = (user: AuthProps): boolean => { + setCookie(COOKIE_KEY, JSON.stringify(user)); + + return true; +}; + +export const deleteAuth = (): boolean => { + deleteCookie(COOKIE_KEY); + + return true; +}; diff --git a/src-migrate/common/libs/clsxm.ts b/src-migrate/common/libs/clsxm.ts new file mode 100644 index 00000000..0fc10317 --- /dev/null +++ b/src-migrate/common/libs/clsxm.ts @@ -0,0 +1,6 @@ +import clsx, { ClassValue } from 'clsx'; +import { twMerge } from 'tw-merge'; + +export default function clsxm(...classes: ClassValue[]) { + return twMerge(clsx(...classes)); +} diff --git a/src-migrate/common/libs/odooApi.ts b/src-migrate/common/libs/odooApi.ts new file mode 100644 index 00000000..2dbc18d3 --- /dev/null +++ b/src-migrate/common/libs/odooApi.ts @@ -0,0 +1,81 @@ +import axios, { AxiosRequestConfig, Method } from 'axios'; +import { getCookie, setCookie } from 'cookies-next'; +import { getAuth } from './auth'; +import { AuthApiProps, AuthProps } from '../types/auth'; + +const ODOO_HOST = process.env.NEXT_PUBLIC_ODOO_API_HOST as string; + +const renewToken = async () => { + let token = await axios.get(`${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: Method, + url: string, + data = {}, + headers = {} +): Promise<any> => { + connectionAttempt++; + + try { + let token = await getToken(); + const auth = getAuth(); + + let axiosParameter: AxiosRequestConfig = { + method, + url: process.env.NEXT_PUBLIC_ODOO_API_HOST + url, + headers: { Authorization: token, ...headers }, + }; + + if (typeof auth === 'object' && 'token' in auth) { + axiosParameter.headers = { + ...axiosParameter.headers, + Token: auth.token, + }; + } + + if (method.toUpperCase() === 'POST') { + axiosParameter.headers = { + ...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); + const authResponse: AuthApiProps = res.data; + + if ( + authResponse.status.code == 401 && + connectionAttempt < maxConnectionAttempt + ) { + await renewToken(); + return odooApi(method, url, data, headers); + } + + return authResponse.result || null; + } catch (error) { + console.log(error); + return null; + } +}; + +export default odooApi; diff --git a/src-migrate/common/stores/useRegisterStore.ts b/src-migrate/common/stores/useRegisterStore.ts new file mode 100644 index 00000000..fcd2cd8b --- /dev/null +++ b/src-migrate/common/stores/useRegisterStore.ts @@ -0,0 +1,52 @@ +import { create } from 'zustand'; +import { RegisterProps } from '../types/auth'; + +type State = { + form: RegisterProps; + isValid: boolean; + isCheckedTNC: boolean; + isOpenTNC: boolean; +}; + +type Action = { + updateForm: (name: string, value: string) => void; + toggleCheckTNC: () => void; + openTNC: () => void; + closeTNC: () => void; +}; + +export const useRegisterStore = create<State & Action>((set) => ({ + form: { + company: '', + name: '', + email: '', + password: '', + }, + isValid: false, + isCheckedTNC: false, + isOpenTNC: false, + updateForm: (name, value) => + set((state) => { + const updatedForm = { ...state.form, [name]: value }; + + const fieldKeys = Object.keys( + updatedForm + ) as (keyof typeof updatedForm)[]; + + const allFieldsValid = fieldKeys.every((key) => { + const value = updatedForm[key]; + + if (key === 'company') return true; + + return value !== ''; + }); + + return { + form: updatedForm, + isValid: allFieldsValid, + }; + }), + toggleCheckTNC: () => set((state) => ({ isCheckedTNC: !state.isCheckedTNC })), + openTNC: () => set(() => ({ isOpenTNC: true })), + closeTNC: () => set(() => ({ isOpenTNC: false })), +})); diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Black.woff b/src-migrate/common/styles/fonts/Inter/Inter-Black.woff Binary files differnew file mode 100644 index 00000000..a18593a0 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Black.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Black.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-Black.woff2 Binary files differnew file mode 100644 index 00000000..68f64c9e --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Black.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-BlackItalic.woff b/src-migrate/common/styles/fonts/Inter/Inter-BlackItalic.woff Binary files differnew file mode 100644 index 00000000..b6b01943 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-BlackItalic.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-BlackItalic.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-BlackItalic.woff2 Binary files differnew file mode 100644 index 00000000..1c9c7ca8 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-BlackItalic.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Bold.woff b/src-migrate/common/styles/fonts/Inter/Inter-Bold.woff Binary files differnew file mode 100644 index 00000000..eaf3d4bf --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Bold.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Bold.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-Bold.woff2 Binary files differnew file mode 100644 index 00000000..2846f29c --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Bold.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-BoldItalic.woff b/src-migrate/common/styles/fonts/Inter/Inter-BoldItalic.woff Binary files differnew file mode 100644 index 00000000..32750761 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-BoldItalic.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-BoldItalic.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-BoldItalic.woff2 Binary files differnew file mode 100644 index 00000000..0b1fe8e1 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-BoldItalic.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-ExtraBold.woff b/src-migrate/common/styles/fonts/Inter/Inter-ExtraBold.woff Binary files differnew file mode 100644 index 00000000..c2c17ede --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-ExtraBold.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-ExtraBold.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-ExtraBold.woff2 Binary files differnew file mode 100644 index 00000000..c24c2bdc --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-ExtraBold.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-ExtraBoldItalic.woff b/src-migrate/common/styles/fonts/Inter/Inter-ExtraBoldItalic.woff Binary files differnew file mode 100644 index 00000000..c42f7052 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-ExtraBoldItalic.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-ExtraBoldItalic.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-ExtraBoldItalic.woff2 Binary files differnew file mode 100644 index 00000000..4a81dc79 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-ExtraBoldItalic.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-ExtraLight.woff b/src-migrate/common/styles/fonts/Inter/Inter-ExtraLight.woff Binary files differnew file mode 100644 index 00000000..d0de5f39 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-ExtraLight.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-ExtraLight.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-ExtraLight.woff2 Binary files differnew file mode 100644 index 00000000..f2ea706f --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-ExtraLight.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-ExtraLightItalic.woff b/src-migrate/common/styles/fonts/Inter/Inter-ExtraLightItalic.woff Binary files differnew file mode 100644 index 00000000..81f1a28e --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-ExtraLightItalic.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-ExtraLightItalic.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-ExtraLightItalic.woff2 Binary files differnew file mode 100644 index 00000000..9af717ba --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-ExtraLightItalic.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Italic.woff b/src-migrate/common/styles/fonts/Inter/Inter-Italic.woff Binary files differnew file mode 100644 index 00000000..a806b382 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Italic.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Italic.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-Italic.woff2 Binary files differnew file mode 100644 index 00000000..a619fc54 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Italic.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Light.woff b/src-migrate/common/styles/fonts/Inter/Inter-Light.woff Binary files differnew file mode 100644 index 00000000..c496464d --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Light.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Light.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-Light.woff2 Binary files differnew file mode 100644 index 00000000..bc4be665 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Light.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-LightItalic.woff b/src-migrate/common/styles/fonts/Inter/Inter-LightItalic.woff Binary files differnew file mode 100644 index 00000000..f84a9de3 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-LightItalic.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-LightItalic.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-LightItalic.woff2 Binary files differnew file mode 100644 index 00000000..842b2dfc --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-LightItalic.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Medium.woff b/src-migrate/common/styles/fonts/Inter/Inter-Medium.woff Binary files differnew file mode 100644 index 00000000..d546843f --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Medium.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Medium.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-Medium.woff2 Binary files differnew file mode 100644 index 00000000..f92498a2 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Medium.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-MediumItalic.woff b/src-migrate/common/styles/fonts/Inter/Inter-MediumItalic.woff Binary files differnew file mode 100644 index 00000000..459a6568 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-MediumItalic.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-MediumItalic.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-MediumItalic.woff2 Binary files differnew file mode 100644 index 00000000..0e3019f4 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-MediumItalic.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Regular.woff b/src-migrate/common/styles/fonts/Inter/Inter-Regular.woff Binary files differnew file mode 100644 index 00000000..62d3a618 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Regular.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Regular.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-Regular.woff2 Binary files differnew file mode 100644 index 00000000..6c2b6893 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Regular.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-SemiBold.woff b/src-migrate/common/styles/fonts/Inter/Inter-SemiBold.woff Binary files differnew file mode 100644 index 00000000..a815f43a --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-SemiBold.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-SemiBold.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-SemiBold.woff2 Binary files differnew file mode 100644 index 00000000..611e90c9 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-SemiBold.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-SemiBoldItalic.woff b/src-migrate/common/styles/fonts/Inter/Inter-SemiBoldItalic.woff Binary files differnew file mode 100644 index 00000000..909e43a9 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-SemiBoldItalic.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-SemiBoldItalic.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-SemiBoldItalic.woff2 Binary files differnew file mode 100644 index 00000000..545685bd --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-SemiBoldItalic.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Thin.woff b/src-migrate/common/styles/fonts/Inter/Inter-Thin.woff Binary files differnew file mode 100644 index 00000000..62bc58cd --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Thin.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-Thin.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-Thin.woff2 Binary files differnew file mode 100644 index 00000000..abbc3a5c --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-Thin.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-ThinItalic.woff b/src-migrate/common/styles/fonts/Inter/Inter-ThinItalic.woff Binary files differnew file mode 100644 index 00000000..700a7f06 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-ThinItalic.woff diff --git a/src-migrate/common/styles/fonts/Inter/Inter-ThinItalic.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-ThinItalic.woff2 Binary files differnew file mode 100644 index 00000000..ab0b2002 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-ThinItalic.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-italic.var.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-italic.var.woff2 Binary files differnew file mode 100644 index 00000000..b826d5af --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-italic.var.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter-roman.var.woff2 b/src-migrate/common/styles/fonts/Inter/Inter-roman.var.woff2 Binary files differnew file mode 100644 index 00000000..6a256a06 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter-roman.var.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/Inter.var.woff2 b/src-migrate/common/styles/fonts/Inter/Inter.var.woff2 Binary files differnew file mode 100644 index 00000000..365eedc5 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/Inter.var.woff2 diff --git a/src-migrate/common/styles/fonts/Inter/inter.css b/src-migrate/common/styles/fonts/Inter/inter.css new file mode 100644 index 00000000..de6ce273 --- /dev/null +++ b/src-migrate/common/styles/fonts/Inter/inter.css @@ -0,0 +1,199 @@ +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 100; + font-display: swap; + src: url('Inter-Thin.woff2?v=3.19') format('woff2'), + url('Inter-Thin.woff?v=3.19') format('woff'); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 100; + font-display: swap; + src: url('Inter-ThinItalic.woff2?v=3.19') format('woff2'), + url('Inter-ThinItalic.woff?v=3.19') format('woff'); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 200; + font-display: swap; + src: url('Inter-ExtraLight.woff2?v=3.19') format('woff2'), + url('Inter-ExtraLight.woff?v=3.19') format('woff'); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 200; + font-display: swap; + src: url('Inter-ExtraLightItalic.woff2?v=3.19') format('woff2'), + url('Inter-ExtraLightItalic.woff?v=3.19') format('woff'); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 300; + font-display: swap; + src: url('Inter-Light.woff2?v=3.19') format('woff2'), + url('Inter-Light.woff?v=3.19') format('woff'); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 300; + font-display: swap; + src: url('Inter-LightItalic.woff2?v=3.19') format('woff2'), + url('Inter-LightItalic.woff?v=3.19') format('woff'); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 400; + font-display: swap; + src: url('Inter-Regular.woff2?v=3.19') format('woff2'), + url('Inter-Regular.woff?v=3.19') format('woff'); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 400; + font-display: swap; + src: url('Inter-Italic.woff2?v=3.19') format('woff2'), + url('Inter-Italic.woff?v=3.19') format('woff'); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url('Inter-Medium.woff2?v=3.19') format('woff2'), + url('Inter-Medium.woff?v=3.19') format('woff'); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url('Inter-MediumItalic.woff2?v=3.19') format('woff2'), + url('Inter-MediumItalic.woff?v=3.19') format('woff'); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 600; + font-display: swap; + src: url('Inter-SemiBold.woff2?v=3.19') format('woff2'), + url('Inter-SemiBold.woff?v=3.19') format('woff'); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 600; + font-display: swap; + src: url('Inter-SemiBoldItalic.woff2?v=3.19') format('woff2'), + url('Inter-SemiBoldItalic.woff?v=3.19') format('woff'); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 700; + font-display: swap; + src: url('Inter-Bold.woff2?v=3.19') format('woff2'), + url('Inter-Bold.woff?v=3.19') format('woff'); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 700; + font-display: swap; + src: url('Inter-BoldItalic.woff2?v=3.19') format('woff2'), + url('Inter-BoldItalic.woff?v=3.19') format('woff'); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 800; + font-display: swap; + src: url('Inter-ExtraBold.woff2?v=3.19') format('woff2'), + url('Inter-ExtraBold.woff?v=3.19') format('woff'); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 800; + font-display: swap; + src: url('Inter-ExtraBoldItalic.woff2?v=3.19') format('woff2'), + url('Inter-ExtraBoldItalic.woff?v=3.19') format('woff'); +} + +@font-face { + font-family: 'Inter'; + font-style: normal; + font-weight: 900; + font-display: swap; + src: url('Inter-Black.woff2?v=3.19') format('woff2'), + url('Inter-Black.woff?v=3.19') format('woff'); +} +@font-face { + font-family: 'Inter'; + font-style: italic; + font-weight: 900; + font-display: swap; + src: url('Inter-BlackItalic.woff2?v=3.19') format('woff2'), + url('Inter-BlackItalic.woff?v=3.19') format('woff'); +} + +/* ------------------------------------------------------- +Variable font. +Usage: + + html { font-family: 'Inter', sans-serif; } + @supports (font-variation-settings: normal) { + html { font-family: 'Inter var', sans-serif; } + } +*/ +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + font-named-instance: 'Regular'; + src: url('Inter-roman.var.woff2?v=3.19') format('woff2'); +} +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + font-named-instance: 'Italic'; + src: url('Inter-italic.var.woff2?v=3.19') format('woff2'); +} + +/* -------------------------------------------------------------------------- +[EXPERIMENTAL] Multi-axis, single variable font. + +Slant axis is not yet widely supported (as of February 2019) and thus this +multi-axis single variable font is opt-in rather than the default. + +When using this, you will probably need to set font-variation-settings +explicitly, e.g. + + * { font-variation-settings: "slnt" 0deg } + .italic { font-variation-settings: "slnt" 10deg } + +*/ +@font-face { + font-family: 'Inter var experimental'; + font-weight: 100 900; + font-display: swap; + font-style: oblique 0deg 10deg; + src: url('Inter.var.woff2?v=3.19') format('woff2'); +} diff --git a/src-migrate/common/styles/globals.css b/src-migrate/common/styles/globals.css new file mode 100644 index 00000000..ea20b247 --- /dev/null +++ b/src-migrate/common/styles/globals.css @@ -0,0 +1,674 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +* { + -webkit-tap-highlight-color: transparent; +} + +html, +body { + @apply w-screen + text-body-2 + text-gray_r-12 + bg-gray_r-1 + overflow-x-clip; +} + +#__next main { + @apply min-h-screen; +} + +button { + @apply block; +} + +@layer base { + input[type='number']::-webkit-inner-spin-button, + input[type='number']::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; + } + + input[type='number'] { + -moz-appearance: textfield; + } +} + +@layer components { + .badge-red, + .badge-solid-red, + .badge-gray, + .badge-yellow, + .badge-blue, + .badge-green, + .badge-solid-green { + @apply text-[11px] + leading-none + font-medium + px-1 + py-1 + rounded + w-fit; + } + + .badge-red { + @apply bg-danger-100 + text-danger-600; + } + + .badge-solid-red { + @apply bg-danger-500 + text-white; + } + + .badge-gray { + @apply bg-gray_r-5 + text-gray_r-10; + } + + .badge-yellow { + @apply bg-warning-500 + text-warning-900; + } + + .badge-blue { + @apply bg-blue-200 + text-blue-600; + } + + .badge-green { + @apply bg-success-100 + text-success-600; + } + + .badge-solid-green { + @apply bg-success-500 + text-white; + } + + .form-label { + @apply font-medium + block; + } + + .form-input { + @apply p-3 + rounded + border + text-gray_r-12 + border-gray_r-7 + !bg-white + bg-transparent + w-full + leading-none + focus:outline-none + focus:border-warning-500 + disabled:bg-gray_r-5; + } + + .form-input[aria-invalid] { + @apply border-danger-500 + focus:border-danger-500; + } + + .form-input[type='file'] { + @apply py-2; + } + + .btn-yellow, + .btn-light, + .btn-red, + .btn-solid-red { + @apply block + w-fit + py-3 + px-6 + rounded + border + text-center + font-medium + ease-linear + duration-150; + } + + .btn-yellow { + @apply bg-warning-500 + border-warning-500 + hover:bg-warning-500/80 + disabled:text-gray_r-10 + disabled:bg-warning-200 + disabled:border-warning-200; + } + + .btn-red { + @apply bg-danger-100 + border-danger-300 + text-danger-500 + disabled:text-danger-400 + disabled:bg-danger-200; + } + + .btn-solid-red { + @apply bg-danger-500 + border-danger-500 + text-gray_r-1 + hover:bg-danger-500/80 + disabled:text-gray_r-1 + disabled:bg-danger-200 + disabled:border-danger-200; + } + + .btn-light { + @apply bg-gray_r-3 + border-gray_r-6 + disabled:text-gray_r-10 + disabled:bg-gray_r-6; + } + + .product-card { + @apply w-full + h-full + border + border-gray_r-3 + shadow + bg-white + rounded + relative + flex + flex-col; + } + + .product-card__image { + @apply w-full + h-[160px] + object-contain + object-center + border-b + border-gray_r-6; + } + + .product-card__content { + @apply p-2 + pb-3 + flex-1; + } + + .product-card__title { + @apply text-caption-1 + text-gray_r-12 + leading-5; + } + + .product-card__brand { + @apply text-caption-1 + mb-1 + block; + } + + .product__description { + @apply text-gray_r-12/90; + } + + .product__description br { + @apply block my-1; + } + + .product__description b { + @apply font-semibold; + } +} + +@layer utilities { + .wrap-line-ellipsis-1, + .wrap-line-ellipsis-2, + .wrap-line-ellipsis-3 { + display: -webkit-box; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; + } + + .wrap-line-ellipsis-1 { + -webkit-line-clamp: 1; + } + + .wrap-line-ellipsis-2 { + -webkit-line-clamp: 2; + } + + .wrap-line-ellipsis-3 { + -webkit-line-clamp: 3; + } +} + +.menu-wrapper { + @apply fixed + top-0 + left-0 + bg-white + w-[80%] + h-full + z-[60] + overflow-y-auto + translate-x-[-100%] + ease-linear + duration-150; +} + +.menu-wrapper.active { + @apply translate-x-0; +} + +.overlay { + @apply fixed + top-0 + left-0 + w-full + h-full + z-[55] + bg-gray_r-12/40; +} + +.sticky-header { + @apply px-4 + py-3 + bg-gray_r-1/90 + backdrop-blur-lg + sticky + top-0 + border-b + border-gray_r-7 + z-50; +} + +.content-container { + @apply max-w-full + overflow-x-hidden; +} + +#indoteknik_toast { + @apply fixed + bottom-4 + translate-y-[200%] + left-[50%] + translate-x-[-50%] + z-[100] + flex + items-center + p-4 + mb-4 + w-[90%] + text-gray-500 + bg-white + border + border-gray-300 + rounded-lg + shadow + ease-linear + duration-300; +} + +#indoteknik_toast.active { + @apply translate-y-0; +} + +.category-menu { + @apply hidden; +} + +.swiper-slide { + @apply !h-auto; +} + +.lazy-load-image-background { + @apply !block + w-full; +} + +.swiper-pagination-bullet-active { + @apply !bg-danger-500; +} + +.pagination { + @apply flex + justify-center + gap-x-1; +} + +.pagination-item { + @apply p-1 + flex + justify-center + items-center + w-10 + rounded + ease-linear + duration-150 + border + border-gray_r-6 + bg-gray_r-3 + hover:bg-gray_r-5 + text-gray_r-12; +} + +.pagination-item--active { + @apply border-warning-500 + bg-warning-500 + hover:bg-warning-500; +} + +.pagination-dots { + @apply p-1 + flex + justify-center + items-end + w-10 + rounded + ease-linear + bg-gray_r-3 + text-caption-2; +} + +.idt-transition { + @apply transition-all + ease-out + duration-200; +} + +.form-select__placeholder { + @apply !text-gray_r-9; +} + +.form-select__control { + @apply !shadow-none + !border-gray_r-7; +} + +.form-select__control--menu-is-open { + @apply !border-warning-500; +} + +.table-specification { + @apply max-h-[500px] overflow-y-auto border border-gray_r-6; +} + +.table-specification > table { + @apply table-auto + border-collapse + w-full; +} + +.table-specification > table > thead > tr > th:last-child { + @apply w-3/12; +} + +.table-specification > table > thead { + @apply sticky top-0 border-b; +} + +.table-specification > table > thead > tr { + @apply bg-gray_r-1/80 backdrop-blur-lg; +} + +.table-specification th { + @apply font-semibold; +} + +.table-specification th, +.table-specification td { + @apply p-4 text-center; +} + +.table-specification > table > tbody > tr { + @apply odd:bg-gray_r-3 even:bg-gray_r-1; +} + +.table-cart, +.table-checkout { + @apply w-full + table-auto + border-collapse; +} + +.table-cart tr, +.table-checkout tr { + @apply border-y + border-gray_r-6 + first:border-t-0; +} + +.table-cart th, +.table-cart td, +.table-checkout th, +.table-checkout td { + @apply py-4 + px-3 + text-center + text-gray_r-12/90; +} + +.table-cart th, +.table-cart td { + @apply first:w-12; +} + +.table-cart th, +.table-checkout th { + @apply font-medium; +} + +.table-data { + @apply w-full + table-auto + border-collapse; +} + +.table-data thead tr { + @apply bg-gray_r-3; +} + +.table-data thead th { + @apply font-medium whitespace-nowrap; +} + +.table-data thead th, +.table-data tbody td { + @apply px-3 + py-4 + text-center; +} + +.table-data tbody td { + @apply text-gray_r-12/90; +} + +.table-data tbody tr { + @apply border-b + border-gray_r-6; +} + +.navbar-user-dropdown-button { + @apply flex-1 + flex + gap-x-2 + p-4 + items-center + bg-danger-500 + font-medium + !text-gray_r-1 + rounded-none + rounded-t-xl; +} + +.navbar-user-dropdown-button span { + @apply line-clamp-1; +} + +.navbar-user-dropdown-wrapper a, +.navbar-user-dropdown-wrapper button { + @apply text-gray_r-12/80 hover:bg-gray_r-5 font-medium py-2 px-4 w-full text-left; +} + +.navbar-user-dropdown { + @apply bg-white + border + border-gray_r-6 + py-2 + w-full + shadow; +} + +.category-mega-box-wrapper, +.navbar-user-dropdown-wrapper { + @apply absolute + opacity-0 + left-0 + top-[125%] + flex + w-full + z-10 + transition-all + ease-in + duration-200 + pointer-events-none + text-left; +} + +.category-mega-box-wrapper.show, +.navbar-user-dropdown-button:hover ~ .navbar-user-dropdown-wrapper, +.navbar-user-dropdown-wrapper:hover { + @apply top-[100%] + opacity-100 + pointer-events-auto; +} + +.category-mega-box { + @apply relative + py-2 + border + border-t-0 + bg-white + border-gray_r-6 + h-full + w-full; +} + +.category-mega-box > div { + @apply text-gray_r-12/80; +} + +.category-mega-box > div:hover .category-mega-box__parent { + @apply bg-gray_r-5; +} + +.category-mega-box > div:hover .category-mega-box__child-wrapper { + @apply opacity-100 + top-0 + pointer-events-auto; +} + +.category-mega-box .category-mega-box__parent { + @apply py-2.5 + px-4 + text-gray_r-12/80 + font-normal; +} + +.category-mega-box__child-wrapper { + @apply absolute + left-[100%] + top-12 + w-[40vw] + bg-gray_r-1/90 + backdrop-blur-md + border + border-gray_r-6 + p-6 + opacity-0 + h-full + transition-all + ease-in + duration-200 + pointer-events-none + z-50; +} + +.category-mega-box__child-one { + @apply text-gray_r-12/80 + hover:text-danger-500 + transition-colors + ease-linear + duration-100 + font-semibold; +} + +.category-mega-box__child-two { + @apply text-gray_r-12/80 + hover:text-danger-500 + transition-colors + ease-linear + duration-100 + font-normal; +} + +@keyframes page-loader { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +.page-loader { + animation-name: page-loader; + animation-duration: 1000ms; + animation-delay: 50ms; + animation-timing-function: ease-in-out; + animation-iteration-count: infinite; +} + +@keyframes shake { + 0% { + transform: translateX(0); + } + 10%, + 90% { + transform: translateX(-10px); + } + 20%, + 80% { + transform: translateX(10px); + } + 30%, + 50%, + 70% { + transform: translateX(-10px); + } + 40%, + 60% { + transform: translateX(10px); + } + 100% { + transform: translateX(0); + } +} + +.blink-color-flash-sale { + @apply text-body-1 md:text-title-sm; + transform: rotateY(180deg) rotateZ(120deg); + animation-name: blink-color-flash-sale; + animation-duration: 300ms; + animation-iteration-count: infinite; + animation-timing-function: linear; +} + +@keyframes blink-color-flash-sale { + from { + @apply text-danger-500; + } + to { + @apply text-warning-500; + } +} diff --git a/src-migrate/common/types/auth.ts b/src-migrate/common/types/auth.ts new file mode 100644 index 00000000..63fac6e0 --- /dev/null +++ b/src-migrate/common/types/auth.ts @@ -0,0 +1,32 @@ +import { OdooApiProps } from './odoo'; + +export type AuthProps = { + id: number; + parent_id: number; + parent_name: string; + partner_id: number; + name: string; + email: string; + phone: string; + mobile: string; + external: boolean; + company: boolean; + pricelist: string | null; + token: string; +}; + +export type AuthApiProps = OdooApiProps & { result: AuthProps }; + +export type RegisterProps = { + name: string; + email: string; + password: string; + company: string; +}; + +export type RegisterApiProps = OdooApiProps & { + result: { + register: boolean; + reason?: 'EMAIL_USED'; + }; +}; diff --git a/src-migrate/common/types/nav.ts b/src-migrate/common/types/nav.ts new file mode 100644 index 00000000..ba97b1bf --- /dev/null +++ b/src-migrate/common/types/nav.ts @@ -0,0 +1,4 @@ +export type SecondaryNavItemProps = { + label: string + href: string +} diff --git a/src-migrate/common/types/odoo.ts b/src-migrate/common/types/odoo.ts new file mode 100644 index 00000000..b34bc667 --- /dev/null +++ b/src-migrate/common/types/odoo.ts @@ -0,0 +1,6 @@ +export type OdooApiProps = { + status: { + code: number; + description: string; + }; +}; diff --git a/src-migrate/common/types/pageContent.ts b/src-migrate/common/types/pageContent.ts new file mode 100644 index 00000000..4361deb7 --- /dev/null +++ b/src-migrate/common/types/pageContent.ts @@ -0,0 +1,5 @@ +export type PageContentProps = { + id: number; + url_path: string; + content: string; +} | null; diff --git a/src-migrate/images/LOGO-INDOTEKNIK-GEAR-GREY.png b/src-migrate/images/LOGO-INDOTEKNIK-GEAR-GREY.png Binary files differnew file mode 100644 index 00000000..2ab07ff5 --- /dev/null +++ b/src-migrate/images/LOGO-INDOTEKNIK-GEAR-GREY.png diff --git a/src-migrate/images/LOGO-INDOTEKNIK-GEAR.png b/src-migrate/images/LOGO-INDOTEKNIK-GEAR.png Binary files differnew file mode 100644 index 00000000..89f749ec --- /dev/null +++ b/src-migrate/images/LOGO-INDOTEKNIK-GEAR.png diff --git a/src-migrate/images/logo.png b/src-migrate/images/logo.png Binary files differnew file mode 100644 index 00000000..dccc0cd6 --- /dev/null +++ b/src-migrate/images/logo.png diff --git a/src-migrate/modules/header/components/HeaderDesktop.tsx b/src-migrate/modules/header/components/HeaderDesktop.tsx new file mode 100644 index 00000000..3860bded --- /dev/null +++ b/src-migrate/modules/header/components/HeaderDesktop.tsx @@ -0,0 +1,82 @@ +import Logo from "~/images/logo.png"; +import { DocumentCheckIcon, HeartIcon } from "@heroicons/react/24/outline"; + +import Image from 'next/image' +import Link from 'next/link' + +// Components +import SearchBar from "./SearchBar"; + +// Constants +import { SECONDARY_MENU_ITEMS } from "~/common/constants/menu"; + +const LOGO_WIDTH = 210; +const LOGO_HEIGHT = LOGO_WIDTH / 3; + +const HeaderDesktop = () => { + return ( + <header> + <nav className="pt-6 sticky top-0 z-50 bg-white border-b-2 border-danger-500"> + <div className="container flex items-center gap-x-6"> + <Link href='/'> + <Image src={Logo} alt="Logo Indoteknik.com" width={LOGO_WIDTH} height={LOGO_HEIGHT} /> + </Link> + + <SearchBar /> + + <div className="flex gap-x-4 items-center"> + <Link + target='_blank' + rel='noreferrer' + href='/my/transactions' + className='flex items-center gap-x-2 !text-gray-900' + > + <DocumentCheckIcon className='w-7' /> + Daftar<br />Quotation + </Link> + + <Link + target='_blank' + rel='noreferrer' + href='/my/wishlist' + className='flex items-center gap-x-2 !text-gray-900' + > + <HeartIcon className='w-7' /> + Wishlist + </Link> + + <a + href={''} + 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> + 0812 8080 622 (Chat) + </div> + </a> + </div> + </div> + + <div className="container mt-6 flex"> + <button type="button" className="w-3/12 p-4 font-semibold border border-gray_r-6 rounded-t-xl flex items-center relative"> + Kategori + </button> + + <nav className="w-6/12 flex px-1 divide-x divide-gray-200"> + {SECONDARY_MENU_ITEMS.map((item, index) => ( + <Link key={index} href={item.href} target="_blank" rel="noreferrer" className="font-medium text-center p-4 flex-1 !text-gray-800 hover:bg-gray-100 transition-all"> + {item.label} + </Link> + ))} + </nav> + + </div> + </nav> + </header> + ) +} + +export default HeaderDesktop
\ No newline at end of file diff --git a/src-migrate/modules/header/components/HeaderMobile.tsx b/src-migrate/modules/header/components/HeaderMobile.tsx new file mode 100644 index 00000000..626f30d7 --- /dev/null +++ b/src-migrate/modules/header/components/HeaderMobile.tsx @@ -0,0 +1,7 @@ +const HeaderMobile = () => { + return ( + <div>HeaderMobile</div> + ) +} + +export default HeaderMobile
\ No newline at end of file diff --git a/src-migrate/modules/header/components/SearchBar.tsx b/src-migrate/modules/header/components/SearchBar.tsx new file mode 100644 index 00000000..ec17abe8 --- /dev/null +++ b/src-migrate/modules/header/components/SearchBar.tsx @@ -0,0 +1,24 @@ + +import { MagnifyingGlassIcon } from '@heroicons/react/24/outline' + +const SearchBar = () => { + return ( + <form className="flex-1 flex items-center"> + <input + type="text" + className="form-input p-3 rounded-r-none border-r-0 border-gray-300 focus:border-gray-300" + placeholder="Ketik nama / part number / merk" + /> + + <button + type="submit" + className="rounded-r border border-l-0 border-gray-300 px-2 py-2.5" + > + <MagnifyingGlassIcon className='w-6' /> + </button> + + </form> + ) +} + +export default SearchBar
\ No newline at end of file diff --git a/src-migrate/modules/header/index.tsx b/src-migrate/modules/header/index.tsx new file mode 100644 index 00000000..5c0e2933 --- /dev/null +++ b/src-migrate/modules/header/index.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import { useWindowSize } from "usehooks-ts" + +import HeaderDesktop from './components/HeaderDesktop' +import HeaderMobile from './components/HeaderMobile' + +const Header = () => { + const { width } = useWindowSize() + + return width > 768 ? <HeaderDesktop /> : <HeaderMobile /> +} + +export default Header
\ No newline at end of file diff --git a/src-migrate/modules/home/components/Home.tsx b/src-migrate/modules/home/components/Home.tsx new file mode 100644 index 00000000..5d3bf104 --- /dev/null +++ b/src-migrate/modules/home/components/Home.tsx @@ -0,0 +1,15 @@ +import VerticalBanner from "./VerticalBanner" + +const Home = () => { + return ( + <> + <div className="container grid"> + <div className="col-span-2"> + <VerticalBanner /> + </div> + </div> + </> + ) +} + +export default Home
\ No newline at end of file diff --git a/src-migrate/modules/home/components/VerticalBanner.tsx b/src-migrate/modules/home/components/VerticalBanner.tsx new file mode 100644 index 00000000..57328037 --- /dev/null +++ b/src-migrate/modules/home/components/VerticalBanner.tsx @@ -0,0 +1,7 @@ +const VerticalBanner = () => { + return ( + <div>VerticalBanner</div> + ) +} + +export default VerticalBanner
\ No newline at end of file diff --git a/src-migrate/modules/home/index.tsx b/src-migrate/modules/home/index.tsx new file mode 100644 index 00000000..6993d9cf --- /dev/null +++ b/src-migrate/modules/home/index.tsx @@ -0,0 +1,3 @@ +import Home from "./components/Home"; + +export default Home
\ No newline at end of file diff --git a/src-migrate/modules/page-content/index.tsx b/src-migrate/modules/page-content/index.tsx new file mode 100644 index 00000000..cbd58633 --- /dev/null +++ b/src-migrate/modules/page-content/index.tsx @@ -0,0 +1,22 @@ +import { useQuery } from "react-query" +import PageContentSkeleton from "~/common/components/skeleton/PageContentSkeleton" +import { PageContentProps } from "~/common/types/pageContent" +import { getPageContent } from "~/services/pageContent" + +type Props = { + path: string +} + +const PageContent = ({ path }: Props) => { + const { data, isLoading } = useQuery<PageContentProps>(`page-content:${path}`, async () => await getPageContent({ path })) + + if (isLoading) { + return <PageContentSkeleton /> + } + + return ( + <div dangerouslySetInnerHTML={{ __html: data?.content || '' }}></div> + ) +} + +export default PageContent
\ No newline at end of file diff --git a/src-migrate/modules/register/components/Form.tsx b/src-migrate/modules/register/components/Form.tsx new file mode 100644 index 00000000..ac194b46 --- /dev/null +++ b/src-migrate/modules/register/components/Form.tsx @@ -0,0 +1,117 @@ +import { ChangeEvent } from "react"; +import { useMutation } from "react-query"; +import { useRegisterStore } from "~/common/stores/useRegisterStore"; +import { RegisterProps } from "~/common/types/auth"; +import { registerUser } from "~/services/auth"; + +const Form = () => { + const { form, isValid, isCheckedTNC, updateForm, toggleCheckTNC, openTNC } = useRegisterStore() + + const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => { + const { name, value } = event.target; + updateForm(name, value) + } + + const mutation = useMutation({ + mutationFn: (data: RegisterProps) => registerUser(data) + }) + + const handleSubmit = async (e: ChangeEvent<HTMLFormElement>) => { + e.preventDefault() + + const response = await mutation.mutateAsync(form) + console.log(response); + + } + + return ( + <form className="mt-6 grid grid-cols-1 gap-y-4" onSubmit={handleSubmit}> + <div> + <label htmlFor="company"> + Nama Perusahaan <span className='text-gray_r-11'>(opsional)</span> + </label> + + <input + type="text" + name="company" + id="company" + className="form-input mt-3" + placeholder="cth: INDOTEKNIK DOTCOM GEMILANG" + autoCapitalize="true" + value={form.company} + onChange={handleInputChange} + /> + </div> + + <div> + <label htmlFor='name'>Nama Lengkap</label> + + <input + type='text' + id='name' + name='name' + className='form-input mt-3' + placeholder='Masukan nama lengkap anda' + value={form.name} + onChange={handleInputChange} + /> + </div> + + <div> + <label htmlFor='email'>Alamat Email</label> + + <input + type='text' + id='email' + name='email' + className='form-input mt-3' + placeholder='Masukan alamat email anda' + value={form.email} + onChange={handleInputChange} + /> + </div> + + <div> + <label htmlFor='password'>Kata Sandi</label> + <input + type='password' + name='password' + id='password' + className='form-input mt-3' + placeholder='••••••••••••' + value={form.password} + onChange={handleInputChange} + /> + </div> + + <div className="mt-4"> + <input + type="checkbox" + name="tnc" + id="tnc" + checked={isCheckedTNC} + onClick={toggleCheckTNC} + /> + <label htmlFor="tnc" className="ml-2 cursor-pointer">Dengan ini saya menyetujui</label> + {' '} + <span + className="font-medium text-danger-500 cursor-pointer" + onClick={openTNC} + > + syarat dan ketentuan + </span> + <label htmlFor="tnc" className="ml-2 cursor-pointer">yang berlaku</label> + </div> + + <button + type="submit" + className="btn-yellow w-full mt-2" + disabled={!isValid || !isCheckedTNC || mutation.isLoading} + > + {mutation.isLoading ? 'Loading...' : 'Daftar'} + </button> + </form> + ) +} + +export default Form
\ No newline at end of file diff --git a/src-migrate/modules/register/components/Register.tsx b/src-migrate/modules/register/components/Register.tsx new file mode 100644 index 00000000..e3e29b9f --- /dev/null +++ b/src-migrate/modules/register/components/Register.tsx @@ -0,0 +1,39 @@ +import PageContent from "~/modules/page-content" +import Form from "./Form" +import Link from "next/link" +import Modal from "~/common/components/elements/Modal" +import TermCondition from "./TermCondition" + +const Register = () => { + return ( + <div className="container"> + <div className="grid grid-cols-1 md:grid-cols-2 gap-x-10 pt-16"> + <section> + <h1 className="text-2xl font-semibold"> + Daftar Akun Indoteknik + </h1> + <h2 className="text-gray_r-11 mt-1 mb-4"> + Buat akun sekarang lebih mudah dan terverifikasi + </h2> + + <Form /> + + <div className='text-gray_r-11 mt-10'> + Sudah punya akun Indoteknik?{' '} + <Link href='/login' className='inline font-medium text-danger-500'> + Masuk + </Link> + </div> + </section> + + <section className="my-10 md:my-0"> + <PageContent path="/register" /> + </section> + </div> + + <TermCondition /> + </div> + ) +} + +export default Register
\ No newline at end of file diff --git a/src-migrate/modules/register/components/TermCondition.tsx b/src-migrate/modules/register/components/TermCondition.tsx new file mode 100644 index 00000000..304ffd69 --- /dev/null +++ b/src-migrate/modules/register/components/TermCondition.tsx @@ -0,0 +1,16 @@ +import React from 'react' +import Modal from '~/common/components/elements/Modal' +import { useRegisterStore } from '~/common/stores/useRegisterStore' +import PageContent from '~/modules/page-content' + +const TermCondition = () => { + const { isOpenTNC, closeTNC } = useRegisterStore() + + return ( + <Modal active={isOpenTNC} close={closeTNC} > + <PageContent path='/register#tnd' /> + </Modal> + ) +} + +export default TermCondition
\ No newline at end of file diff --git a/src-migrate/modules/register/index.tsx b/src-migrate/modules/register/index.tsx new file mode 100644 index 00000000..ba5efa3a --- /dev/null +++ b/src-migrate/modules/register/index.tsx @@ -0,0 +1,3 @@ +import Register from "./components/Register"; + +export default Register
\ No newline at end of file diff --git a/src-migrate/pages/_app.tsx b/src-migrate/pages/_app.tsx new file mode 100644 index 00000000..2dc82559 --- /dev/null +++ b/src-migrate/pages/_app.tsx @@ -0,0 +1,7 @@ +import '~/common/styles/fonts/Inter/inter.css' +import '~/common/styles/globals.css' +import type { AppProps } from "next/app" + +export default function MyApp({ Component, pageProps }: AppProps) { + return <Component {...pageProps} /> +}
\ No newline at end of file diff --git a/src-migrate/pages/register.tsx b/src-migrate/pages/register.tsx new file mode 100644 index 00000000..4ba72cbc --- /dev/null +++ b/src-migrate/pages/register.tsx @@ -0,0 +1,13 @@ + +import BasicLayout from "@/core/components/layouts/BasicLayout" +import Register from "~/modules/register" + +const RegisterPage = () => { + return ( + <BasicLayout> + <Register /> + </BasicLayout> + ) +} + +export default RegisterPage
\ No newline at end of file diff --git a/src-migrate/services/auth.ts b/src-migrate/services/auth.ts new file mode 100644 index 00000000..f2fd7761 --- /dev/null +++ b/src-migrate/services/auth.ts @@ -0,0 +1,10 @@ +import odooApi from '~/common/libs/odooApi'; +import { RegisterApiProps, RegisterProps } from '~/common/types/auth'; + +export const registerUser = async ( + data: RegisterProps +): Promise<RegisterApiProps> => { + const response = await odooApi('POST', '/api/v1/user/register', data); + + return response; +}; diff --git a/src-migrate/services/banner.ts b/src-migrate/services/banner.ts new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src-migrate/services/banner.ts diff --git a/src-migrate/services/pageContent.ts b/src-migrate/services/pageContent.ts new file mode 100644 index 00000000..24f2c2f0 --- /dev/null +++ b/src-migrate/services/pageContent.ts @@ -0,0 +1,14 @@ +import odooApi from '~/common/libs/odooApi'; + +export const getPageContent = async ({ path }: { path: string }) => { + const params = new URLSearchParams({ + url_path: path, + }); + + const pageContent = await odooApi( + 'GET', + `/api/v1/page-content?${params.toString()}` + ); + + return pageContent; +}; diff --git a/src/pages/register.jsx b/src/pages/register.jsx index a2fbbf94..f79d6a4e 100644 --- a/src/pages/register.jsx +++ b/src/pages/register.jsx @@ -1,25 +1,11 @@ -import Seo from '@/core/components/Seo' -import SimpleFooter from '@/core/components/elements/Footer/SimpleFooter' -import BasicLayout from '@/core/components/layouts/BasicLayout' -import DesktopView from '@/core/components/views/DesktopView' -import MobileView from '@/core/components/views/MobileView' -import RegisterComponent from '@/lib/auth/components/Register' +import Seo from '@/core/components/Seo'; +import SimpleFooter from '@/core/components/elements/Footer/SimpleFooter'; +import BasicLayout from '@/core/components/layouts/BasicLayout'; +import DesktopView from '@/core/components/views/DesktopView'; +import MobileView from '@/core/components/views/MobileView'; +import RegisterComponent from '@/lib/auth/components/Register'; +import RegisterPage from '~/pages/register'; export default function Register() { - return ( - <> - <Seo title='Register - Indoteknik.com' /> - - <DesktopView> - <BasicLayout> - <RegisterComponent /> - </BasicLayout> - </DesktopView> - - <MobileView> - <RegisterComponent /> - <SimpleFooter /> - </MobileView> - </> - ) + return <RegisterPage />; } diff --git a/tailwind.config.js b/tailwind.config.js index 9b180a90..f1c740d5 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,9 +1,15 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: ['./src/**/*.{js,ts,jsx,tsx}'], + content: [ + './src/**/*.{js,ts,jsx,tsx}', + './src-migrate/**/*.{js,ts,jsx,tsx}' + ], plugins: [require('flowbite/plugin')], darkMode: 'class', theme: { + container: { + center: true + }, extend: { typography: { DEFAULT: { diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..b2e205a3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,41 @@ +{ + "compilerOptions": { + "target": "ES5", + "lib": [ + "DOM", + "DOM.Iterable", + "ESNext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "ESNext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "~/*": ["./src-migrate/*"], + "@/*": ["./src/*"] + }, + "forceConsistentCasingInFileNames": true + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], + "exclude": [ + "node_modules", + "src" + ] +} |
