betang payment
4
.env.development
Normal file
@ -0,0 +1,4 @@
|
||||
NEXT_PUBLIC_API_URL='https://sam-kalteng-api.basys.co.id'
|
||||
NEXT_PUBLIC_API_URL_NEWS='https://cors-anywhere.herokuapp.com/https://newsapi.org/v2'
|
||||
NEXT_PUBLIC_API_URL_NEWS_MEDIASTACK='https://api.mediastack.com/v1'
|
||||
NEXT_PUBLIC_API_URL_NEWS_NEWDATA='https://newsdata.io/api/1'
|
4
.env.production
Normal file
@ -0,0 +1,4 @@
|
||||
NEXT_PUBLIC_API_URL='https://sam-kalteng-api.basys.co.id'
|
||||
NEXT_PUBLIC_API_URL_NEWS='https://cors-anywhere.herokuapp.com/https://newsapi.org/v2'
|
||||
NEXT_PUBLIC_API_URL_NEWS_MEDIASTACK='https://api.mediastack.com/v1'
|
||||
NEXT_PUBLIC_API_URL_NEWS_NEWDATA='https://newsdata.io/api/1'
|
@ -1,3 +1,7 @@
|
||||
{
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
||||
"extends": "next",
|
||||
"rules": {
|
||||
"react/no-unescaped-entities": "off",
|
||||
"@next/next/no-page-custom-font": "off"
|
||||
}
|
||||
}
|
4
.idea/watcherTasks.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectTasksOptions" suppressed-tasks="SCSS" />
|
||||
</project>
|
@ -1,5 +1,6 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: false,
|
||||
output: 'export',
|
||||
images: {
|
||||
loader: "custom",
|
||||
|
147
package-lock.json
generated
@ -15,7 +15,9 @@
|
||||
"next-image-export-optimizer": "^1.12.3",
|
||||
"nextjs-toploader": "^1.6.6",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
"react-dom": "^18",
|
||||
"react-hook-form": "^7.52.2",
|
||||
"sass": "^1.77.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8",
|
||||
@ -1348,6 +1350,18 @@
|
||||
"react-dom": ">=16.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
@ -1572,6 +1586,17 @@
|
||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
@ -1586,7 +1611,6 @@
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
@ -1668,6 +1692,40 @@
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar/node_modules/glob-parent": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/classnames": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||
@ -2663,7 +2721,6 @@
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
@ -2761,6 +2818,19 @@
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
@ -3067,6 +3137,11 @@
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
|
||||
"integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw=="
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
@ -3187,6 +3262,17 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-binary-path": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-boolean-object": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
|
||||
@ -3264,7 +3350,6 @@
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@ -3308,7 +3393,6 @@
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
|
||||
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-extglob": "^2.1.1"
|
||||
},
|
||||
@ -3344,7 +3428,6 @@
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
@ -3859,6 +3942,14 @@
|
||||
"react-dom": ">= 16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/normalize-path": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nprogress": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz",
|
||||
@ -4125,7 +4216,6 @@
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
},
|
||||
@ -4817,11 +4907,37 @@
|
||||
"react": "^18.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/react-hook-form": {
|
||||
"version": "7.52.2",
|
||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.52.2.tgz",
|
||||
"integrity": "sha512-pqfPEbERnxxiNMPd0bzmt1tuaPcVccywFDpyk2uV5xCIBphHV5T8SVnX9/o3kplPE1zzKt77+YIoq+EMwJp56A==",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/react-hook-form"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17 || ^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/reflect.getprototypeof": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
|
||||
@ -5011,6 +5127,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.77.8",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz",
|
||||
"integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==",
|
||||
"dependencies": {
|
||||
"chokidar": ">=3.0.0 <4.0.0",
|
||||
"immutable": "^4.0.0",
|
||||
"source-map-js": ">=0.6.2 <2.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"sass": "sass.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
@ -5493,7 +5625,6 @@
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
|
@ -5,6 +5,7 @@
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build && next-image-export-optimizer",
|
||||
"build:dev": "NODE_ENV=development next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"dev-export": "next dev -H 0.0.0.0 -p 3000",
|
||||
@ -13,12 +14,14 @@
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^5.4.0",
|
||||
"antd": "^5.20.0",
|
||||
"framer-motion": "^10.16.4",
|
||||
"next": "14.2.5",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"next-image-export-optimizer": "^1.12.3",
|
||||
"nextjs-toploader": "^1.6.6",
|
||||
"framer-motion": "^10.16.4"
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
"react-hook-form": "^7.52.2",
|
||||
"sass": "^1.77.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^8",
|
||||
|
307
public/css/form.css
Normal file
@ -0,0 +1,307 @@
|
||||
.form-control {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 10px 17px;
|
||||
height: 40px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
border-radius: 20px;
|
||||
color: #181c32;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e1e3ea;
|
||||
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.ant-select-selection-item {
|
||||
font-weight: 600 !important;
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.ant-select-disabled {
|
||||
background: #fff;
|
||||
border: 0;
|
||||
|
||||
.ant-select-selector {
|
||||
background: #fff !important;
|
||||
color: #181c32 !important;
|
||||
}
|
||||
|
||||
.ant-select-arrow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.ant-picker-disabled {
|
||||
background-color: #fff !important;
|
||||
border: 0;
|
||||
|
||||
input {
|
||||
color: #181c32 !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.form-control {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
.form-control[type="file"] {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.form-control[type="file"]:not(:disabled):not([readonly]) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
color: #181c32;
|
||||
background-color: #ffffff;
|
||||
border-color: var(#b5b5c3);
|
||||
outline: 0;
|
||||
/* box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.08); */
|
||||
}
|
||||
|
||||
.form-control::-webkit-date-and-time-value {
|
||||
height: 1.5em;
|
||||
}
|
||||
|
||||
.form-control::placeholder {
|
||||
font-size: 14px;
|
||||
color: #a1a5b7;
|
||||
font-weight: 400;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.form-control:disabled,
|
||||
.form-control[readonly] {
|
||||
background-color: #fff;
|
||||
border: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* ======== FLOATING LABEL ======== */
|
||||
|
||||
.floating-label-content {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.floating-label-content textarea {
|
||||
min-height: 120px;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.floating-label {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
padding: 0 7px;
|
||||
background: #fff;
|
||||
color: #757575;
|
||||
cursor: text;
|
||||
transition: 0.2s ease all;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.floating-input:focus,
|
||||
.floating-select:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.floating-input:focus~.floating-label {
|
||||
top: -10px;
|
||||
left: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.floating-input:not(:-moz-placeholder-shown)~.floating-label {
|
||||
top: -10px;
|
||||
left: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.floating-input:not(:-ms-input-placeholder)~.floating-label {
|
||||
top: -10px;
|
||||
left: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.floating-input:not(:placeholder-shown)~.floating-label {
|
||||
top: -10px;
|
||||
left: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.floating-select:not([value=""]):valid~.floating-label {
|
||||
top: -10px;
|
||||
left: 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 120px;
|
||||
padding: 14px 20px;
|
||||
}
|
||||
|
||||
/* ======== END FLOATING LABEL ======== */
|
||||
|
||||
.label-form {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #1f2233;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.icon-password {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
color: #c1c1c1;
|
||||
top: 0px;
|
||||
font-size: 25px;
|
||||
border-radius: 27px;
|
||||
}
|
||||
|
||||
/* INPUT IMAGE */
|
||||
.image-input {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.image-input .content-btn {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
left: -11px;
|
||||
top: -10px;
|
||||
gap: 3px;
|
||||
flex-direction: column;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.image-input input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.image-input label {
|
||||
display: block;
|
||||
color: #FFF;
|
||||
background: #000;
|
||||
padding: 0.3rem 0.6rem;
|
||||
font-size: 115%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.image-input label i {
|
||||
font-size: 125%;
|
||||
margin-right: 0.3rem;
|
||||
}
|
||||
|
||||
.image-input label:hover i {
|
||||
animation: shake 0.35s;
|
||||
}
|
||||
|
||||
// .ant-upload-wrapper .ant-upload {
|
||||
// background-size: contain !important;
|
||||
// width: 100% !important;
|
||||
// height: 200px !important;
|
||||
// border-radius: 20px;
|
||||
// border: 1px dashed #f1f1f1;
|
||||
// }
|
||||
|
||||
.image-input span {
|
||||
display: none;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.image-preview{
|
||||
width: 100%;
|
||||
height: 315px;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
// .ant-image-mask-info {
|
||||
// border-radius: 20px;
|
||||
// }
|
||||
|
||||
@keyframes shake {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
25% {
|
||||
transform: rotate(10deg);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
75% {
|
||||
transform: rotate(-10deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* INPUT IMAGE */
|
||||
|
||||
|
||||
.searchInput {
|
||||
border-radius: 20px;
|
||||
padding-left: 2.6rem;
|
||||
background-color: #fff !important;
|
||||
transition: all 0.2s;
|
||||
width: 100px;
|
||||
border: 1px solid #0049af24;
|
||||
height: 37px;
|
||||
}
|
||||
|
||||
.searchInput:focus {
|
||||
background-color: #fff !important;
|
||||
width: 300px !important;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
|
||||
.icon-search {
|
||||
position: absolute;
|
||||
top: 11px;
|
||||
left: 13px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.error-form {
|
||||
font-size: 11px;
|
||||
color: var(--danger);
|
||||
margin-top: 5px;
|
||||
margin-left: 22px;
|
||||
}
|
||||
|
||||
.error .form-control {
|
||||
border: 1px solid var(--danger);
|
||||
}
|
||||
|
||||
.error .floating-label {
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.ant-select-selector {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.ant-select-selection-search {
|
||||
left: 0 !important;
|
||||
}
|
@ -38,6 +38,8 @@
|
||||
}
|
||||
|
||||
|
||||
@import "form.css";
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 5px;
|
||||
height: 14px;
|
||||
@ -111,6 +113,12 @@ button, input {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.btn-dark{
|
||||
background: #ffffff;
|
||||
color: #59b8b6;
|
||||
border: 1px solid #59b8b6;
|
||||
}
|
||||
|
||||
.title-wrap {
|
||||
position: relative;
|
||||
display: flex;
|
||||
@ -143,7 +151,7 @@ button, input {
|
||||
.no-data{
|
||||
text-align: center;
|
||||
padding: 30px 20px;
|
||||
background: #f5f5f5;
|
||||
background: #f5f5f58f;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 20px;
|
||||
@ -173,7 +181,7 @@ button, input {
|
||||
/*color: #fff;*/
|
||||
/*background: var(--primary-gradient);*/
|
||||
color: var(--primary);
|
||||
background: #f5f5f5;
|
||||
background: #f5f5f58f;
|
||||
padding: 10px 15px;
|
||||
margin-bottom: -12px;
|
||||
border-radius: 20px 20px 0 0;
|
||||
@ -201,7 +209,7 @@ button, input {
|
||||
|
||||
.ant-tabs-content-holder {
|
||||
/*background: var(--primary-gradient);*/
|
||||
background: #f5f5f5;
|
||||
background: #f5f5f58f;
|
||||
padding: 20px;
|
||||
border-radius: 0 20px 20px 20px;
|
||||
}
|
||||
@ -285,23 +293,26 @@ button, input {
|
||||
|
||||
.search {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
left: 15px;
|
||||
top:10px;
|
||||
z-index: 200;
|
||||
width: 70%;
|
||||
width: 61%;
|
||||
|
||||
.form {
|
||||
border-radius: 30px;
|
||||
border: 1px solid #fff;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper > input.ant-input,
|
||||
.ant-input-affix-wrapper >
|
||||
input.ant-input,
|
||||
.ant-input-affix-wrapper > textarea.ant-input {
|
||||
font-weight: 600 !important;
|
||||
font-weight: 400 !important;
|
||||
color: #353535 !important;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.anticon svg {
|
||||
.anticon
|
||||
svg {
|
||||
fill: var(--primary);
|
||||
margin-right: 10px;
|
||||
}
|
||||
@ -312,14 +323,13 @@ button, input {
|
||||
|
||||
.header {
|
||||
background: linear-gradient(to bottom, #49B1B5, #149A9F);
|
||||
height: 200px;
|
||||
height: 160px;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center; /* Horizontally center */
|
||||
align-items: center; /* Vertically center */
|
||||
|
||||
/*border-radius: 0 0 50px 50px;*/
|
||||
|
||||
&.hidden {
|
||||
@ -337,10 +347,10 @@ button, input {
|
||||
width: 100% !important;
|
||||
left: 0 !important;
|
||||
bottom: 0px !important;
|
||||
top: 200px !important;
|
||||
top: 145px !important;
|
||||
border: none !important;
|
||||
z-index: 1;
|
||||
height: unset !important;
|
||||
height: 90px !important;
|
||||
}
|
||||
|
||||
|
||||
@ -353,16 +363,36 @@ button, input {
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin-top: 80px;
|
||||
|
||||
text-align: center;
|
||||
img {
|
||||
width: 300px;
|
||||
width: 30px !important;
|
||||
margin-bottom: -30px;
|
||||
margin-right: -99px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 400;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 66px;
|
||||
/* background: #00000033; */
|
||||
/* padding: 8px 0 0 15px; */
|
||||
/* border-radius: 20px; */
|
||||
|
||||
.title{
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.sub-title{
|
||||
font-size: 10px;
|
||||
font-weight: 300;
|
||||
margin-top: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
.top-btn {
|
||||
@ -385,10 +415,10 @@ button, input {
|
||||
}
|
||||
|
||||
.location {
|
||||
margin-top: 10px;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 20px;
|
||||
z-index: 111;
|
||||
|
||||
|
||||
|
||||
.title {
|
||||
font-size: 12px;
|
||||
@ -396,49 +426,76 @@ button, input {
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 400;
|
||||
}
|
||||
;
|
||||
left: 15px;
|
||||
bottom: 35px;
|
||||
top: 12px;
|
||||
height: 26px;
|
||||
background: #ffffff26;
|
||||
padding: 4px 20px;
|
||||
border-radius: 28px;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper >
|
||||
input.ant-input:hover + .search{
|
||||
background: red;
|
||||
}
|
||||
|
||||
.search {
|
||||
margin-top: 7px;
|
||||
padding: 0 40px;
|
||||
padding: 0px 79px;
|
||||
position: absolute;
|
||||
z-index: 200;
|
||||
|
||||
|
||||
|
||||
.form {
|
||||
border-radius: 15px;
|
||||
border-radius: 40px;
|
||||
padding: 10px 25px;
|
||||
border: none;
|
||||
box-shadow: 0 6px 15px #00000026;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper > input.ant-input,
|
||||
.ant-input-affix-wrapper >
|
||||
input.ant-input,
|
||||
.ant-input-affix-wrapper > textarea.ant-input {
|
||||
font-weight: 600 !important;
|
||||
font-weight: 500 !important;
|
||||
color: #353535 !important;
|
||||
font-size: 12px;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
.anticon svg {
|
||||
.anticon
|
||||
svg {
|
||||
fill: var(--primary);
|
||||
margin-right: 10px;
|
||||
}
|
||||
;
|
||||
bottom: -23px;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.omnichannel {
|
||||
margin-top: 120px;
|
||||
margin-top: 100px;
|
||||
padding: 0 25px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.card-omni {
|
||||
/*background: #fff;*/
|
||||
/* background: #fff; */
|
||||
background: linear-gradient(to bottom, #fff, #f3feff);
|
||||
border-radius: 20px;
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
border: 1px solid #eeeeee;
|
||||
padding: 10px 10px 20px;
|
||||
/*box-shadow: 9px 10px 18px #d7d7d7;*/
|
||||
/*border: 1px solid #eeeeee;*/
|
||||
padding: 10px 10px 15px;
|
||||
box-shadow: 9px 10px 18px #d7d7d75e;
|
||||
|
||||
.icon {
|
||||
img {
|
||||
@ -455,7 +512,9 @@ button, input {
|
||||
height: 30px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.news {
|
||||
@ -541,9 +600,11 @@ button, input {
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
background: #f5f5f5;
|
||||
background: #f5f5f58f;
|
||||
padding: 10px 10px 5px;
|
||||
border-radius: 15px;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
|
||||
.image {
|
||||
border-radius: 10px;
|
||||
@ -591,4 +652,139 @@ button, input {
|
||||
color: #fff;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detail-berita{
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
padding-top: 48px;
|
||||
|
||||
.content-detail{
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.img img{
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.title{
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
text-align: justify;
|
||||
}
|
||||
.description{
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 40px;
|
||||
text-align: justify;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.detail-va{
|
||||
table {
|
||||
font-size: 12px;
|
||||
width: 100%;
|
||||
|
||||
.title{
|
||||
font-weight: 400;
|
||||
width: 40% !important;
|
||||
}
|
||||
|
||||
.value{
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-checkbox-wrapper-disabled {
|
||||
cursor: not-allowed;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ant-table-wrapper .ant-table-thead >tr>th,
|
||||
.ant-table-wrapper .ant-table-thead >tr>td {
|
||||
//color: #fff;
|
||||
//background: #4fb4b5;
|
||||
color: #51b5b5;
|
||||
background: #51b5b536;
|
||||
}
|
||||
|
||||
.ant-table-wrapper .ant-table-tbody .ant-table-row.ant-table-row-selected >.ant-table-cell {
|
||||
background: #daefef57;
|
||||
}
|
||||
|
||||
.notes{
|
||||
margin: 50px 0 10px;
|
||||
font-size: 10px;
|
||||
font-weight: 400;
|
||||
color: var(--text-muted);
|
||||
text-align: justify;
|
||||
}
|
||||
}
|
||||
|
||||
hr.border{
|
||||
border: 1px dashed #e5e5e5;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.ant-checkbox-checked .ant-checkbox-inner {
|
||||
background-color: #58b8b6 !important;
|
||||
border-color: #58b8b6 !important;
|
||||
}
|
||||
|
||||
.zn-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 12px;
|
||||
background: #fff;
|
||||
|
||||
tr th{
|
||||
padding: 10px 30px;
|
||||
color: #51b5b5;
|
||||
background: #51b5b536;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
tr td {
|
||||
text-align: left;
|
||||
padding: 10px 30px;
|
||||
border-top: 1px solid #ededed;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
tfoot tr td{
|
||||
background: #e2ffe3;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-payment{
|
||||
|
||||
.title{
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--primary);
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.sub-title {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-modal .ant-modal-content {
|
||||
border-radius: 15px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
public/image/layer3.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
public/image/logodummy.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
public/image/nextImageExportOptimizer/layer3-opt-10.WEBP
Normal file
After Width: | Height: | Size: 70 B |
BIN
public/image/nextImageExportOptimizer/layer3-opt-1080.WEBP
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
public/image/nextImageExportOptimizer/layer3-opt-1200.WEBP
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
public/image/nextImageExportOptimizer/layer3-opt-128.WEBP
Normal file
After Width: | Height: | Size: 380 B |
BIN
public/image/nextImageExportOptimizer/layer3-opt-16.WEBP
Normal file
After Width: | Height: | Size: 82 B |
BIN
public/image/nextImageExportOptimizer/layer3-opt-1920.WEBP
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
public/image/nextImageExportOptimizer/layer3-opt-2048.WEBP
Normal file
After Width: | Height: | Size: 5.4 KiB |
BIN
public/image/nextImageExportOptimizer/layer3-opt-256.WEBP
Normal file
After Width: | Height: | Size: 598 B |
BIN
public/image/nextImageExportOptimizer/layer3-opt-32.WEBP
Normal file
After Width: | Height: | Size: 128 B |
BIN
public/image/nextImageExportOptimizer/layer3-opt-384.WEBP
Normal file
After Width: | Height: | Size: 874 B |
BIN
public/image/nextImageExportOptimizer/layer3-opt-3840.WEBP
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
public/image/nextImageExportOptimizer/layer3-opt-48.WEBP
Normal file
After Width: | Height: | Size: 152 B |
BIN
public/image/nextImageExportOptimizer/layer3-opt-64.WEBP
Normal file
After Width: | Height: | Size: 194 B |
BIN
public/image/nextImageExportOptimizer/layer3-opt-640.WEBP
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
public/image/nextImageExportOptimizer/layer3-opt-750.WEBP
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
public/image/nextImageExportOptimizer/layer3-opt-828.WEBP
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
public/image/nextImageExportOptimizer/layer3-opt-96.WEBP
Normal file
After Width: | Height: | Size: 262 B |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-10.WEBP
Normal file
After Width: | Height: | Size: 198 B |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-1080.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-1200.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-128.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-16.WEBP
Normal file
After Width: | Height: | Size: 368 B |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-1920.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-2048.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-256.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-32.WEBP
Normal file
After Width: | Height: | Size: 916 B |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-384.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-3840.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-48.WEBP
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-64.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-640.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-750.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-828.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
public/image/nextImageExportOptimizer/logodummy-opt-96.WEBP
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -5,7 +5,9 @@
|
||||
"image/grouplogo.png": "nVetjZphqR92a3EwnYIlVQcTWHXwzxEeUsfFrZ59W9g=",
|
||||
"image/layer1.png": "QTEGhbVeWDTZQ+JWYULiLkETaWi0ybiI78gEMC-QL40=",
|
||||
"image/layer2.png": "LfddDhf5OGLWosggG0KrRuBq5afq-1sLUBLYpRgryAk=",
|
||||
"image/layer3.png": "a05J2QHjZFTOhXBnlUDVYsXMGxuTVma0aR1skHSj37Y=",
|
||||
"image/logo.png": "guyrxmHxHTV4YYqWnO5sapp8aB6Gr2jARr5b-eA-Jao=",
|
||||
"image/logodummy.png": "dVLj+C82snmcMrm1xUqwzw8zmXmSSGJtOKiaOaFqspo=",
|
||||
"image/logonew.png": "zLpohFmIYCjwIAZ7n-egh6QTt9zue1N-d-69M8Fnses=",
|
||||
"image/memphis-colorful.webp": "fHLKCUhSbSismaq1wl2nOnpiuWVohmsMEMX-H8z5Sro=",
|
||||
"image/sports.webp": "n2DZ2RqxVBlVqJ6uPWYlSVPgBPbrdUUdNGYU3uFlnuU=",
|
||||
|
270
src/app/betangPayment/detailVA.jsx
Normal file
@ -0,0 +1,270 @@
|
||||
import {useState} from "react";
|
||||
import {Table, message, Modal, Input} from "antd";
|
||||
import {Helper} from "@/lib/Helper";
|
||||
import TransitionContent from "@/component/TransitionContent";
|
||||
|
||||
export default function DetailVA() {
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [modalPin, setModalPin] = useState(false)
|
||||
const [statusPIN, setStatusPIN] = useState(false)
|
||||
const [pin, setPin] = useState(null)
|
||||
const [messageApi, contextHolder] = message.useMessage();
|
||||
const [selectedRow, setSelectedRow] = useState([])
|
||||
const [dataDetail, setDataDetail] = useState({
|
||||
institusi:'Hasanka',
|
||||
nama:'Bagus',
|
||||
kelas:'2',
|
||||
nomorVA:'1029381029380129'
|
||||
})
|
||||
|
||||
const rowSelection = {
|
||||
onChange: (selectedRowKeys, selectedRows) => {
|
||||
setSelectedRow(selectedRows)
|
||||
// console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
|
||||
},
|
||||
getCheckboxProps: (record) => ({
|
||||
disabled: record.paymentStatus === 1,
|
||||
}),
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'Nama Produk',
|
||||
dataIndex: 'namaProduk',
|
||||
},
|
||||
{
|
||||
title: 'Total Tagihan',
|
||||
dataIndex: 'tagihan',
|
||||
align:'right',
|
||||
render: (text) => <span>{Helper.numFormat(text)}</span>,
|
||||
},
|
||||
{
|
||||
title: 'Keterangan',
|
||||
dataIndex: 'keterangan',
|
||||
},
|
||||
];
|
||||
const data = [
|
||||
{
|
||||
id: '1',
|
||||
namaProduk: 'SPP Januari 2024',
|
||||
tagihan: 200000,
|
||||
keterangan: 'Terbayar',
|
||||
paymentStatus: 1
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
namaProduk: 'SPP Februari 2024',
|
||||
tagihan: 30000,
|
||||
keterangan: 'Belum Terbayar',
|
||||
paymentStatus: 0
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
namaProduk: 'Uang Pembangunan',
|
||||
tagihan: 400000,
|
||||
keterangan: 'Belum Terbayar',
|
||||
paymentStatus: 0
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
namaProduk: 'Uang Pakaian',
|
||||
tagihan: 200000,
|
||||
keterangan: 'Belum Terbayar',
|
||||
paymentStatus: 0
|
||||
},
|
||||
];
|
||||
|
||||
const actPayment = () => {
|
||||
if(selectedRow.length === 0){
|
||||
messageApi.open({
|
||||
type: 'warning',
|
||||
content: 'Pilih Produk Terlebih Dahulu',
|
||||
});
|
||||
return false
|
||||
}
|
||||
|
||||
setIsModalOpen(true)
|
||||
}
|
||||
|
||||
const actModalPIN = () => {
|
||||
setIsModalOpen(false)
|
||||
setModalPin(true)
|
||||
setStatusPIN(false)
|
||||
}
|
||||
|
||||
const sendPin = () => {
|
||||
console.log(pin)
|
||||
|
||||
if(pin === null){
|
||||
messageApi.open({
|
||||
type: 'warning',
|
||||
content: 'PIN Tidak Sesuai',
|
||||
});
|
||||
setPin(null)
|
||||
return false
|
||||
}
|
||||
|
||||
setStatusPIN(true)
|
||||
setPin(null)
|
||||
}
|
||||
|
||||
const actSendPayment = () => {
|
||||
console.log('send payment')
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return(
|
||||
<>
|
||||
<TransitionContent>
|
||||
{contextHolder}
|
||||
<div className={"detail-va"}>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className={"title"}>Nama Institusi</td>
|
||||
<td className={"value"}>: {dataDetail?.institusi}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className={"title"}>Nama Lengkap</td>
|
||||
<td className={"value"}>: {dataDetail?.nama}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className={"title"}>Kelas</td>
|
||||
<td className={"value"}>: {dataDetail?.kelas}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className={"title"}>Nomor VA</td>
|
||||
<td className={"value"}>: {dataDetail?.nomorVA}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<hr className={"border"}/>
|
||||
|
||||
<Table
|
||||
rowSelection={{
|
||||
type: 'checkbox',
|
||||
...rowSelection,
|
||||
}}
|
||||
columns={columns}
|
||||
dataSource={data}
|
||||
rowKey={"id"}
|
||||
pagination={false}
|
||||
/>
|
||||
|
||||
<div style={{display:'flex',gap:'10px',marginTop:'30px'}}>
|
||||
{/*<button className={"button btn-full btn-dark"}>Batal</button>*/}
|
||||
<button onClick={actPayment} className={"button btn-full"}>Bayar</button>
|
||||
</div>
|
||||
</div>
|
||||
</TransitionContent>
|
||||
|
||||
<Modal open={isModalOpen} closeIcon={false} footer={null} >
|
||||
<div className={"modal-payment"}>
|
||||
<div className={"title"}>Detail Pembayaran</div>
|
||||
<div className={"sub-title"}>Daftar Produk yang akan dibayarkan</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className={"detail-va"} style={{marginTop:'20px'}}>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className={"title"}>Nama Institusi</td>
|
||||
<td className={"value"}>: {dataDetail?.institusi}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className={"title"}>Nama Lengkap</td>
|
||||
<td className={"value"}>: {dataDetail?.nama}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className={"title"}>Kelas</td>
|
||||
<td className={"value"}>: {dataDetail?.kelas}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className={"title"}>Total Tagihan</td>
|
||||
<td className={"value"}>: {Helper.numFormat(selectedRow.reduce((sum, current) => sum + current.tagihan, 0))}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table className={"zn-table"} style={{marginTop:'30px'}}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Keterangan</th>
|
||||
<th style={{textAlign:'right'}}>Tagihan</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{selectedRow?.map((v,k) => (
|
||||
<tr key={k}>
|
||||
<td>{v.namaProduk}</td>
|
||||
<td style={{textAlign:'right'}}>{Helper.numFormat(v.tagihan)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div className={"notes"}>Apakah data yang dipilih sudah benar ? pastikan cek data terlebih dahulu dan klik tombol bayar untuk melakukan pembayaran</div>
|
||||
<div style={{display:'flex',gap:'10px',marginTop:'30px'}}>
|
||||
|
||||
<button onClick={()=>setIsModalOpen(false)} className={"button btn-full btn-dark"}>Batal</button>
|
||||
<button onClick={actSendPayment} className={"button btn-full"}>Bayar</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Modal>
|
||||
|
||||
<Modal open={modalPin} closeIcon={false} footer={null}>
|
||||
|
||||
|
||||
{(statusPIN) ?
|
||||
<TransitionContent>
|
||||
<div>
|
||||
<div className={"modal-payment"} style={{textAlign:"center"}}>
|
||||
<div className={"title"}>BERHASIL</div>
|
||||
<div className={"sub-title"} style={{marginTop:'10px'}}>Transaksi Berhasil, silahkan lakukan pembayaran <br/> melalui <b>Mobile Banking</b> </div>
|
||||
<a href={"#"} className={"button btn-full"} style={{marginTop:'20px'}}>Buka Mobile Banking</a>
|
||||
</div>
|
||||
</div>
|
||||
</TransitionContent>
|
||||
:
|
||||
<TransitionContent>
|
||||
<div>
|
||||
<div className={"modal-payment"} style={{textAlign:"center"}}>
|
||||
<div className={"title"}>PIN SMS</div>
|
||||
<div className={"sub-title"}>Masukan PIN SMS anda</div>
|
||||
</div>
|
||||
|
||||
<div style={{marginTop:'30px'}}>
|
||||
<Input.OTP variant={"filled"} size={"large"} value={pin} type={"number"} length={6} onKeyPress={(event) => {
|
||||
if (!/[0-9]/.test(event.key)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}} onChange={(text)=>setPin(text)} />
|
||||
|
||||
</div>
|
||||
|
||||
<div style={{display:'flex',gap:'10px',marginTop:'30px'}}>
|
||||
|
||||
<button onClick={()=>setModalPin(false)} className={"button btn-full btn-dark"}>Batal</button>
|
||||
<button onClick={sendPin} className={"button btn-full"}>OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</TransitionContent>
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
47
src/app/betangPayment/inquiryVA.jsx
Normal file
@ -0,0 +1,47 @@
|
||||
"use client"
|
||||
import {useForm} from "react-hook-form";
|
||||
import Input from "@/component/Input";
|
||||
import {motion} from "framer-motion";
|
||||
import LoadingPage from "@/component/LoadingPage";
|
||||
|
||||
|
||||
export default function InquiryVA({sendNoVA}) {
|
||||
const {
|
||||
register, handleSubmit, reset, setValue, formState: {errors},
|
||||
} = useForm();
|
||||
|
||||
const submitVA = (data) => {
|
||||
sendNoVA(data)
|
||||
}
|
||||
|
||||
return(
|
||||
<>
|
||||
<motion.div
|
||||
className={"animate-box"}
|
||||
initial={{ opacity: 0, y: 0 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 0 }}
|
||||
transition={{
|
||||
duration: 1,
|
||||
ease: "easeInOut",
|
||||
times: [0, 0.5, 1],
|
||||
loop: Infinity,
|
||||
repeatDelay: 1
|
||||
}}
|
||||
>
|
||||
<Input.Number
|
||||
title={'Nomor VA'}
|
||||
name={'nomorVA'}
|
||||
minlength={3}
|
||||
maxlength={20}
|
||||
setReadonly={false}
|
||||
required={true}
|
||||
register={register}
|
||||
error={errors}
|
||||
/>
|
||||
<button onClick={handleSubmit(submitVA)} className={"button btn-full"}>Inquiry No VA</button>
|
||||
</motion.div>
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
44
src/app/betangPayment/page.jsx
Normal file
@ -0,0 +1,44 @@
|
||||
"use client"
|
||||
import MainLayout from "@/component/MainLayout";
|
||||
import {useEffect, useState} from "react";
|
||||
import {CloseOutlined, LeftOutlined} from "@ant-design/icons";
|
||||
import Link from "next/link";
|
||||
import InquiryVA from "@/app/betangPayment/inquiryVA";
|
||||
import DetailVA from "@/app/betangPayment/detailVA";
|
||||
|
||||
|
||||
export default function Page() {
|
||||
const [statusVA, setStatusVA] = useState(false)
|
||||
|
||||
const sendNoVA = (va) => {
|
||||
console.log(va)
|
||||
setStatusVA(true)
|
||||
}
|
||||
|
||||
return (<>
|
||||
<MainLayout>
|
||||
<section className={`header-small`} style={{background: "var(--primary-gradient)", backdropFilter: "blur(8px)"}}>
|
||||
<div className={"top-btn close"}>
|
||||
<CloseOutlined style={{marginTop: '7px'}}/>
|
||||
</div>
|
||||
<div className={"search"} style={{marginLeft: '50px', marginTop: '4px', fontSize: '13px', fontWeight: '600'}}>
|
||||
Betang Payment
|
||||
</div>
|
||||
<Link href={"/"} className={"top-btn back"} style={{color:'#fff'}}>
|
||||
<LeftOutlined style={{marginTop: '7px'}}/>
|
||||
</Link>
|
||||
</section>
|
||||
<section style={{height: "100vh", padding: '80px 30px'}}>
|
||||
{(statusVA) ?
|
||||
<DetailVA/>
|
||||
:
|
||||
<InquiryVA sendNoVA={sendNoVA}/>
|
||||
}
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
</MainLayout>
|
||||
</>)
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
"use client"
|
||||
import HeaderSmall from "@/app/component/HeaderSmall";
|
||||
import {Col, Row, Tabs} from "antd";
|
||||
import {ShoppingOutlined} from "@ant-design/icons";
|
||||
import HeaderSmallDetail from "@/app/component/HeaderSmallDetail";
|
||||
import NoData from "@/app/component/NoData";
|
||||
import MainLayout from "@/app/component/MainLayout";
|
||||
import ExportedImage from "next-image-export-optimizer";
|
||||
|
||||
export default function page() {
|
||||
|
||||
const onChange = () => {
|
||||
|
||||
}
|
||||
|
||||
const CardOmni = () => {
|
||||
return (<Row gutter={[10, 10]}>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/garuda.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Garuda Indonesia</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/traveloka.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Traveloka</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/woos.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Woosh</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/kai.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>KAI</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/garuda.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Garuda Indonesia</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/traveloka.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Traveloka</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/woos.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Woosh</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/kai.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>KAI</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/garuda.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Garuda Indonesia</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/traveloka.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Traveloka</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/woos.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Woosh</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/kai.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>KAI</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/garuda.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Garuda Indonesia</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/traveloka.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Traveloka</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/woos.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Woosh</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/kai.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>KAI</div>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: '1', label: 'Fashion & Kecantikan ', children: <CardOmni/>,
|
||||
}, {
|
||||
key: '2', label: 'Rekreasi', children: <NoData/>,
|
||||
}, {
|
||||
key: '3', label: 'Donasi & Zakat', children: 'Tidak Ada Data',
|
||||
}, {
|
||||
key: '4', label: 'Hobi & Event', children: 'Tidak Ada Data',
|
||||
}, {
|
||||
key: '5', label: 'Travel', children: 'Tidak Ada Data',
|
||||
}, {
|
||||
key: '6', label: 'Elektronik & Barang Digital ', children: 'Tidak Ada Data',
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
return(
|
||||
<MainLayout>
|
||||
<HeaderSmallDetail/>
|
||||
|
||||
<section className={"omnichannel"}>
|
||||
|
||||
<div className={"list"}>
|
||||
<Tabs defaultActiveKey="1" items={items} onChange={onChange}/>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
<ExportedImage alt={"layer bottom"} className={"layer-bottom"} src={"/image/layer2.png"} fill={true} />
|
||||
</MainLayout>
|
||||
)
|
||||
}
|
@ -1,164 +1,57 @@
|
||||
"use client"
|
||||
import HeaderSmallDetail from "@/app/component/HeaderSmallDetail";
|
||||
import {Tabs} from "antd";
|
||||
import NoData from "@/app/component/NoData";
|
||||
import MainLayout from "@/app/component/MainLayout";
|
||||
import MainLayout from "@/component/MainLayout";
|
||||
import ExportedImage from "next-image-export-optimizer";
|
||||
import {CloseOutlined, LeftOutlined} from "@ant-design/icons";
|
||||
import Link from "next/link";
|
||||
import {useEffect, useState} from "react";
|
||||
import {API} from "@/lib/API";
|
||||
|
||||
export default function page() {
|
||||
export default function Page() {
|
||||
const [dataDetail, setDataDetail] = useState(null)
|
||||
|
||||
const onChange = () => {
|
||||
const getDataDetail = async () => {
|
||||
|
||||
let queryString = window.location.search;
|
||||
let urlParams = new URLSearchParams(queryString);
|
||||
let idBerita = urlParams.get('id')
|
||||
|
||||
let res = await API.GET_NEWS('/latest?id=' + idBerita)
|
||||
setDataDetail(res?.result?.results[0])
|
||||
}
|
||||
|
||||
const ListBerita = () => {
|
||||
return (<>
|
||||
<div className={"list-news"}>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</>)
|
||||
}
|
||||
|
||||
const items = [{
|
||||
key: '1', label: 'Semua ', children: <ListBerita/>,
|
||||
}, {
|
||||
key: '2', label: 'Olahraga', children: <NoData/>,
|
||||
}, {
|
||||
key: '3', label: 'Dunia', children: <NoData/>,
|
||||
}, {
|
||||
key: '4', label: 'Ekonomi', children: <NoData/>,
|
||||
}, {
|
||||
key: '5', label: 'Keluarga', children: <NoData/>,
|
||||
}, {
|
||||
key: '6', label: 'Politik', children: <NoData/>,
|
||||
},
|
||||
|
||||
];
|
||||
useEffect(() => {
|
||||
getDataDetail()
|
||||
}, []);
|
||||
|
||||
return (<MainLayout>
|
||||
|
||||
<HeaderSmallDetail/>
|
||||
|
||||
<section className={"news"} style={{paddingBottom: '100px'}}>
|
||||
<div className={"list"} style={{marginTop: '100px'}}>
|
||||
<Tabs defaultActiveKey="1" items={items} onChange={onChange}/>
|
||||
<section className={`header-small`} style={{background: "#ffffff75", backdropFilter: "blur(8px)"}}>
|
||||
<div className={"top-btn close"}>
|
||||
<CloseOutlined style={{marginTop: '7px', color: '#000'}}/>
|
||||
</div>
|
||||
<div className={"search"} style={{marginLeft: '50px', marginTop: '4px', color: '#000', fontSize: '13px', fontWeight: '600'}}>
|
||||
{dataDetail?.source_name}
|
||||
</div>
|
||||
<Link href={"/"} className={"top-btn back"}>
|
||||
<LeftOutlined style={{marginTop: '7px', color: '#000'}}/>
|
||||
</Link>
|
||||
</section>
|
||||
<section className={"detail-berita"}>
|
||||
<div className={"img"}><img src={dataDetail?.image_url}/></div>
|
||||
<div className={"content-detail"}>
|
||||
<div className={"title"}>{dataDetail?.title}</div>
|
||||
<div className={"description"}>{dataDetail?.description}</div>
|
||||
<div>
|
||||
<a className={"button btn-full"} href={dataDetail?.link} target={"_blank"}>Link Sumber</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/*<iframe style={{height: '100vh', width: '100%'}} src={dataDetail?.url}/>*/}
|
||||
</section>
|
||||
|
||||
<ExportedImage alt={"layer bottom"} className={"layer-bottom"} src={"/image/layer2.png"} fill={true} />
|
||||
|
||||
<ExportedImage alt={"layer bottom"} className={"layer-bottom"} src={"/image/layer2.png"} fill={true}/>
|
||||
|
||||
</MainLayout>)
|
||||
}
|
49
src/app/detailPayment/page.jsx
Normal file
@ -0,0 +1,49 @@
|
||||
"use client"
|
||||
import MainLayout from "@/component/MainLayout";
|
||||
import ExportedImage from "next-image-export-optimizer";
|
||||
import {CloseOutlined, LeftOutlined} from "@ant-design/icons";
|
||||
import Link from "next/link";
|
||||
import {useEffect, useState} from "react";
|
||||
|
||||
export default function Page() {
|
||||
|
||||
const [paymnetData, setPaymnetData] = useState({
|
||||
name: '', url: ''
|
||||
})
|
||||
|
||||
const getPaymentData = async () => {
|
||||
let queryString = window.location.search;
|
||||
let urlParams = new URLSearchParams(queryString);
|
||||
let id = urlParams.get('id')
|
||||
|
||||
setPaymnetData({
|
||||
name: "Telkomsel", url: 'https://www.telkomsel.com/shops/channel/o2o?utm_source=wec&utm_medium=inapp&utm_campaign=omni-bankkalteng&target=bankkalteng&theme=bankkalteng&embed=on'
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getPaymentData()
|
||||
}, []);
|
||||
|
||||
return (<MainLayout>
|
||||
|
||||
<section className={`header-small`} style={{background: "#ffffff75", backdropFilter: "blur(8px)"}}>
|
||||
<div className={"top-btn close"}>
|
||||
<CloseOutlined style={{marginTop: '7px', color: '#000'}}/>
|
||||
</div>
|
||||
<div className={"search"} style={{marginLeft: '50px', marginTop: '4px', color: '#000', fontSize: '13px', fontWeight: '600'}}>
|
||||
{paymnetData?.name}
|
||||
</div>
|
||||
<Link href={"/"} className={"top-btn back"}>
|
||||
<LeftOutlined style={{marginTop: '7px', color: '#000'}}/>
|
||||
</Link>
|
||||
</section>
|
||||
<section style={{paddingTop: '30px', background: '#fff'}}>
|
||||
<iframe style={{height: "calc(100vh - 30px)",width:"100%"}} src={paymnetData?.url}/>
|
||||
</section>
|
||||
|
||||
|
||||
{/*<ExportedImage alt={"layer bottom"} className={"layer-bottom"} src={"/image/layer2.png"} fill={true}/>*/}
|
||||
|
||||
</MainLayout>)
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import "./globals.css";
|
||||
import "@@/css/globals.scss";
|
||||
import localFont from 'next/font/local'
|
||||
import LoadingPage from "@/app/component/LoadingPage";
|
||||
import LoadingPage from "@/component/LoadingPage";
|
||||
|
||||
|
||||
const poppins = localFont({
|
||||
@ -36,8 +36,9 @@ const poppins = localFont({
|
||||
|
||||
|
||||
export const metadata = {
|
||||
title: "Omnichannel Kalteng",
|
||||
title: "Betang Portal Payment Kalteng",
|
||||
description: "Web Omnichannel",
|
||||
|
||||
icons: {
|
||||
icon: '/image/logo.png',
|
||||
shortcut: '/image/logo.png',
|
||||
@ -50,6 +51,7 @@ export const viewport = {
|
||||
width: 'device-width',
|
||||
initialScale: 1,
|
||||
maximumScale: 1,
|
||||
themeColor: "#159B9F"
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
|
111
src/app/listBelanja/page.jsx
Normal file
@ -0,0 +1,111 @@
|
||||
"use client"
|
||||
import HeaderSmall from "@/component/HeaderSmall";
|
||||
import {Col, Row, Tabs} from "antd";
|
||||
import {CreditCardOutlined, ShoppingOutlined} from "@ant-design/icons";
|
||||
import HeaderSmallDetail from "@/component/HeaderSmallDetail";
|
||||
import NoData from "@/component/NoData";
|
||||
import MainLayout from "@/component/MainLayout";
|
||||
import ExportedImage from "next-image-export-optimizer";
|
||||
import Link from "next/link";
|
||||
import {useEffect, useState} from "react";
|
||||
|
||||
export default function Page() {
|
||||
const [listPayment, setListPayment] = useState([])
|
||||
|
||||
|
||||
const getListPayment = () => {
|
||||
const dataDummy = [
|
||||
{
|
||||
id:1,
|
||||
name:'Traveloka Hotel',
|
||||
logo:'/logo/traveloka.png'
|
||||
},
|
||||
{
|
||||
id:2,
|
||||
name:'Traveloka Flight',
|
||||
logo:'/logo/traveloka.png'
|
||||
},
|
||||
{
|
||||
id:3,
|
||||
name:'KAI',
|
||||
logo:'/logo/kai.png'
|
||||
},
|
||||
{
|
||||
id:4,
|
||||
name:'Virtual Account',
|
||||
logo:null
|
||||
},
|
||||
{
|
||||
id:5,
|
||||
name:'Telkomsel',
|
||||
logo:null
|
||||
}
|
||||
]
|
||||
|
||||
setListPayment(dataDummy)
|
||||
}
|
||||
|
||||
|
||||
const onChange = () => {
|
||||
|
||||
}
|
||||
|
||||
const CardOmni = () => {
|
||||
return (<Row gutter={[10, 10]}>
|
||||
|
||||
{listPayment?.map((v,k) => (
|
||||
<Col span={6} key={k}>
|
||||
<Link href={`/detailPayment?id=${v?.id}`} className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
{(v?.logo) ?
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={v?.logo} fill={true} />
|
||||
:
|
||||
<CreditCardOutlined style={{color:'var(--primary)',fontSize:'20px',height:'40px'}} />
|
||||
}
|
||||
</div>
|
||||
<div className={"title"}>{v?.name}</div>
|
||||
</Link>
|
||||
</Col>
|
||||
))}
|
||||
|
||||
</Row>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: '1', label: 'Semua ', children: <CardOmni/>,
|
||||
}, {
|
||||
key: '2', label: 'Rekreasi', children: <NoData/>,
|
||||
}, {
|
||||
key: '3', label: 'Donasi & Zakat', children: 'Tidak Ada Data',
|
||||
}, {
|
||||
key: '4', label: 'Hobi & Event', children: 'Tidak Ada Data',
|
||||
}, {
|
||||
key: '5', label: 'Travel', children: 'Tidak Ada Data',
|
||||
}, {
|
||||
key: '6', label: 'Elektronik & Barang Digital ', children: 'Tidak Ada Data',
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
getListPayment()
|
||||
}, []);
|
||||
|
||||
return(
|
||||
<MainLayout>
|
||||
<HeaderSmallDetail/>
|
||||
|
||||
<section className={"omnichannel"}>
|
||||
|
||||
<div className={"list"}>
|
||||
<Tabs defaultActiveKey="1" items={items} onChange={onChange}/>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
<ExportedImage alt={"layer bottom"} className={"layer-bottom"} src={"/image/layer2.png"} fill={true} />
|
||||
</MainLayout>
|
||||
)
|
||||
}
|
76
src/app/listBerita/page.jsx
Normal file
@ -0,0 +1,76 @@
|
||||
"use client"
|
||||
import HeaderSmallDetail from "@/component/HeaderSmallDetail";
|
||||
import {Tabs} from "antd";
|
||||
import NoData from "@/component/NoData";
|
||||
import MainLayout from "@/component/MainLayout";
|
||||
import ExportedImage from "next-image-export-optimizer";
|
||||
import {API} from "@/lib/API";
|
||||
import {useEffect, useState} from "react";
|
||||
import Link from "next/link";
|
||||
import {Helper} from "@/lib/Helper";
|
||||
|
||||
export default function Page() {
|
||||
const [listNews, setListNews] = useState()
|
||||
|
||||
const getNews = async () => {
|
||||
let res = await API.GET_NEWS('/latest?country=id')
|
||||
setListNews(res?.result?.results)
|
||||
}
|
||||
|
||||
|
||||
const onChange = () => {
|
||||
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getNews()
|
||||
}, []);
|
||||
|
||||
const ListBerita = () => {
|
||||
return (<div className={"list-news"}>
|
||||
{listNews?.map((v,k) => (
|
||||
<Link href={`/detailBerita?id=${v?.article_id}`} className={"content-list-news"} key={k}>
|
||||
<div>
|
||||
<img alt={v?.image_url} className={"image-export image"} src={v?.image_url} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>{v?.category?.toString()}</div>
|
||||
<div className={"title"}>{Helper.limitString(v?.title,30) }</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>{v?.source_name}</span> | { Helper.getDifferenceDate(new Date(),v?.pubDate) }</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
|
||||
</div>)
|
||||
}
|
||||
|
||||
const items = [{
|
||||
key: '1', label: 'Semua ', children: <ListBerita/>,
|
||||
}, {
|
||||
key: '2', label: 'Olahraga', children: <NoData/>,
|
||||
}, {
|
||||
key: '3', label: 'Dunia', children: <NoData/>,
|
||||
}, {
|
||||
key: '4', label: 'Ekonomi', children: <NoData/>,
|
||||
}, {
|
||||
key: '5', label: 'Keluarga', children: <NoData/>,
|
||||
}, {
|
||||
key: '6', label: 'Politik', children: <NoData/>,
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
return (<MainLayout>
|
||||
|
||||
<HeaderSmallDetail/>
|
||||
|
||||
<section className={"news"} style={{paddingBottom: '100px'}}>
|
||||
<div className={"list"} style={{marginTop: '100px'}}>
|
||||
<Tabs defaultActiveKey="1" items={items} onChange={onChange}/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<ExportedImage alt={"layer bottom"} className={"layer-bottom"} src={"/image/layer2.png"} fill={true} />
|
||||
|
||||
</MainLayout>)
|
||||
}
|
275
src/app/page.js
@ -1,18 +1,73 @@
|
||||
"use client"
|
||||
import {Carousel, Col, Input, Row, Tabs} from "antd";
|
||||
import {BellOutlined, CloseOutlined, EnvironmentOutlined, ReadOutlined, SearchOutlined, ShoppingOutlined} from "@ant-design/icons";
|
||||
import {BellOutlined, CloseOutlined, CreditCardOutlined, EnvironmentOutlined, MoneyCollectFilled, ReadOutlined, SearchOutlined, ShoppingOutlined} from "@ant-design/icons";
|
||||
import {useEffect, useState} from "react";
|
||||
import Header from "@/app/component/Header";
|
||||
import HeaderSmall from "@/app/component/HeaderSmall";
|
||||
import Header from "@/component/Header";
|
||||
import HeaderSmall from "@/component/HeaderSmall";
|
||||
import Link from "next/link";
|
||||
import LoadingPage from "@/app/component/LoadingPage";
|
||||
import MainLayout from "@/app/component/MainLayout";
|
||||
import LoadingPage from "@/component/LoadingPage";
|
||||
import MainLayout from "@/component/MainLayout";
|
||||
import ExportedImage from "next-image-export-optimizer";
|
||||
import {API} from "@/lib/API";
|
||||
import {Helper} from "@/lib/Helper";
|
||||
import NoData from "@/component/NoData";
|
||||
|
||||
export default function Home() {
|
||||
const [isVisible, setIsVisible] = useState(true);
|
||||
const [listPayment, setListPayment] = useState([])
|
||||
const [listNews, setListNews] = useState([])
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const getListPayment = () => {
|
||||
const dataDummy = [
|
||||
{
|
||||
id:1,
|
||||
name:'Traveloka Hotel',
|
||||
logo:'/logo/traveloka.png',
|
||||
url:null
|
||||
},
|
||||
{
|
||||
id:2,
|
||||
name:'Traveloka Flight',
|
||||
logo:'/logo/traveloka.png',
|
||||
url:null
|
||||
},
|
||||
{
|
||||
id:3,
|
||||
name:'KAI',
|
||||
logo:'/logo/kai.png',
|
||||
url:null
|
||||
},
|
||||
{
|
||||
id:4,
|
||||
name:'Virtual Account',
|
||||
logo:null,
|
||||
url:null
|
||||
},
|
||||
{
|
||||
id:5,
|
||||
name:'Telkomsel',
|
||||
logo:null,
|
||||
url:null
|
||||
},
|
||||
{
|
||||
id:6,
|
||||
name:'Betang Payment',
|
||||
logo:null,
|
||||
url:'/betangPayment'
|
||||
}
|
||||
]
|
||||
|
||||
setListPayment(dataDummy)
|
||||
}
|
||||
|
||||
const getNews = async () => {
|
||||
let res = await API.GET_NEWS('/latest?country=id')
|
||||
setListNews(res?.result?.results)
|
||||
}
|
||||
|
||||
const scrollEffect = () => {
|
||||
const handleScroll = () => {
|
||||
if (window.scrollY > 150) {
|
||||
setIsVisible(false);
|
||||
@ -26,100 +81,75 @@ export default function Home() {
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
scrollEffect()
|
||||
getListPayment()
|
||||
// getNews()
|
||||
|
||||
}, []);
|
||||
|
||||
const onChange = (key) => {
|
||||
console.log(key);
|
||||
};
|
||||
|
||||
|
||||
const CardOmni = () => {
|
||||
return (<Row gutter={[10, 10]}>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/garuda.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Garuda Indonesia</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/traveloka.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Traveloka</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/woos.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Woosh</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/kai.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>KAI</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/garuda.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Garuda Indonesia</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/traveloka.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Traveloka</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/woos.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>Woosh</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<div className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={"/logo/kai.png"} fill={true} />
|
||||
</div>
|
||||
<div className={"title"}>KAI</div>
|
||||
</div>
|
||||
</Col>
|
||||
|
||||
{listPayment.map((v,k) => (
|
||||
<Col span={6} key={k}>
|
||||
<Link href={(v?.url) ? v?.url:`/detailPayment?id=${v?.id}`} className={"card-omni"}>
|
||||
<div className={"icon"}>
|
||||
{(v?.logo) ?
|
||||
<ExportedImage alt={"card omni"} className={"image-export"} src={v?.logo} fill={true} />
|
||||
:
|
||||
<CreditCardOutlined style={{color:'var(--primary)',fontSize:'20px',height:'40px'}} />
|
||||
}
|
||||
</div>
|
||||
<div className={"title"}>{v?.name}</div>
|
||||
</Link>
|
||||
</Col>
|
||||
))}
|
||||
|
||||
</Row>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
const dummy = [
|
||||
{
|
||||
idKategori:'xxx',
|
||||
namaKategori:'xxx',
|
||||
menu:[
|
||||
{
|
||||
id:1,
|
||||
name:'Traveloka Hotel',
|
||||
logo:'/logo/traveloka.png',
|
||||
url:null
|
||||
},
|
||||
{
|
||||
id:2,
|
||||
name:'Traveloka Flight',
|
||||
logo:'/logo/traveloka.png',
|
||||
url:null
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: '1', label: 'Fashion & Kecantikan ', children: <CardOmni/>,
|
||||
key: '1', label: 'Semua ', children: <CardOmni/>,
|
||||
}, {
|
||||
key: '2', label: 'Rekreasi', children: 'Tidak Ada Data',
|
||||
key: '2', label: 'Rekreasi', children: <NoData/>,
|
||||
}, {
|
||||
key: '3', label: 'Donasi & Zakat', children: 'Tidak Ada Data',
|
||||
key: '3', label: 'Donasi & Zakat', children: <NoData/>,
|
||||
}, {
|
||||
key: '4', label: 'Hobi & Event', children: 'Tidak Ada Data',
|
||||
key: '4', label: 'Hobi & Event', children: <NoData/>,
|
||||
}, {
|
||||
key: '5', label: 'Travel', children: 'Tidak Ada Data',
|
||||
key: '5', label: 'Travel', children: <NoData/>,
|
||||
}, {
|
||||
key: '6', label: 'Elektronik & Barang Digital ', children: 'Tidak Ada Data',
|
||||
key: '6', label: 'Elektronik & Barang Digital ', children: <NoData/>,
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
return (<>
|
||||
@ -134,11 +164,11 @@ export default function Home() {
|
||||
<div className={"title"}>Waktunya Belanja</div>
|
||||
<div className={"sub-title"}>Semua yang Kamu perlu, ada di sini</div>
|
||||
</div>
|
||||
<Link href={"/detailBelanja"} className={"button"} type={"button"}>Lihat Semua</Link>
|
||||
<Link href={"/listBelanja"} className={"button"} type={"button"}>Lihat Semua</Link>
|
||||
</div>
|
||||
|
||||
<div className={"list"}>
|
||||
<Tabs defaultActiveKey="1" items={items} onChange={onChange}/>
|
||||
<Tabs defaultActiveKey="1" items={items} />
|
||||
</div>
|
||||
|
||||
</section>
|
||||
@ -153,70 +183,45 @@ export default function Home() {
|
||||
</div>
|
||||
|
||||
<div className={"slider"}>
|
||||
<Carousel arrows infinite={true}>
|
||||
<div className={"berita"}>
|
||||
<div className={"layer-berita"}></div>
|
||||
<ExportedImage alt={"berita"} className={"image-export img"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
<div className={"content-berita"}>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi PR Maresca</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={"berita"}>
|
||||
<div className={"layer-berita"}></div>
|
||||
<ExportedImage alt={"berita"} className={"image-export img"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
<div className={"content-berita"}>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi PR Maresca</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
</div>
|
||||
{(listNews) ?
|
||||
<Carousel arrows infinite={true}>
|
||||
{listNews?.slice(0,5)?.map((v,k) => (
|
||||
<Link href={`/detailBerita?id=${v?.article_id}`} className={"berita"} key={k}>
|
||||
<div className={"layer-berita"}></div>
|
||||
<img alt={v?.image_url} className={"image-export img"} src={v?.image_url} />
|
||||
<div className={"content-berita"}>
|
||||
{/*<div className={"category"}>{v?.category?.toString()}</div>*/}
|
||||
<div className={"title"}>{v?.title}</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>{v?.source_name}</span> | { Helper.getDifferenceDate(new Date(),v?.pubDate) }</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</Carousel>:'loading...' }
|
||||
|
||||
</Carousel>
|
||||
</div>
|
||||
|
||||
<div className={"list-news"}>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
{listNews?.slice(5,10)?.map((v,k) => (
|
||||
<Link href={`/detailBerita?id=${v?.article_id}`} className={"content-list-news"} key={k}>
|
||||
<div>
|
||||
<img alt={v?.image_url} className={"image-export image"} src={v?.image_url} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>{v?.category?.toString()}</div>
|
||||
<div className={"title"}>{Helper.limitString(v?.title,30) }</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>{v?.source_name}</span> | { Helper.getDifferenceDate(new Date(),v?.pubDate) }</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={"content-list-news"}>
|
||||
<div>
|
||||
<ExportedImage alt={"berita"} className={"image-export image"} src={"/berita/berita.jpeg"} fill={true} />
|
||||
</div>
|
||||
<div>
|
||||
<div className={"category"}>Olahraga</div>
|
||||
<div className={"title"}>Chelsea Keropos, Lini Belakang Jadi...</div>
|
||||
<div className={"subtitle"}><span className={"sumber"}>Detik.com</span> | 30 Menit yang lalu</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<Link href={"/detailBerita"} className={"button btn-full"} type={"button"}>Lihat Semua</Link>
|
||||
<Link href={"/listBerita"} className={"button btn-full"} type={"button"}>Lihat Semua</Link>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className={"footer"}>
|
||||
<div className={"title"}>produk atau jasa di menu omnichannel disediakan dan sepenuhnya menjadi tanggungjawab penyedia produk atau jasa terkait. baca syarat dan ketentuan lengkap disini</div>
|
||||
<div className={"title"}>produk atau jasa di menu Betang Portal Payment disediakan dan sepenuhnya menjadi tanggungjawab penyedia produk atau jasa terkait. baca syarat dan ketentuan lengkap disini</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
@ -1,14 +1,46 @@
|
||||
import {BellOutlined, CloseOutlined, EnvironmentOutlined, SearchOutlined} from "@ant-design/icons";
|
||||
import {Input} from "antd";
|
||||
import ExportedImage from "next-image-export-optimizer";
|
||||
import {useEffect, useState} from "react";
|
||||
|
||||
export default function Header({isVisible}) {
|
||||
const [location, setLocation] = useState()
|
||||
|
||||
const getLocation = async () => {
|
||||
|
||||
if ("geolocation" in navigator) {
|
||||
navigator.geolocation.getCurrentPosition(
|
||||
async (position) => {
|
||||
|
||||
let response = await fetch(`https://geocode.maps.co/reverse?lat=${position.coords.latitude}&lon=${position.coords.longitude}`);
|
||||
const locationName = await response.json();
|
||||
console.log(locationName)
|
||||
|
||||
setLocation({
|
||||
latitude: position.coords.latitude,
|
||||
longitude: position.coords.longitude,
|
||||
name:`${locationName.address.village}, ${locationName.address.city}`
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
setError(error.message);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
setError("Geolocation is not supported by this browser.");
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log(location)
|
||||
}, [location]);
|
||||
|
||||
return(
|
||||
<>
|
||||
<section className={`header ${isVisible ? 'visible' : 'hidden'}`}>
|
||||
<div className={"location"}>
|
||||
<div onClick={getLocation} className={"location"}>
|
||||
<div className={"value"}><EnvironmentOutlined style={{marginRight: '5px'}}/>
|
||||
Kota Bandung, Jawa Barat
|
||||
{(location?.name) ? location?.name:"Aktifkan Lokasi"}
|
||||
</div>
|
||||
</div>
|
||||
<div className={"top-btn notification"}>
|
||||
@ -23,15 +55,17 @@ export default function Header({isVisible}) {
|
||||
<div>
|
||||
<ExportedImage
|
||||
className={"image-export"}
|
||||
src="/image/logonew.png"
|
||||
src="/image/logodummy.png"
|
||||
fill={true}
|
||||
alt="logo"
|
||||
/>
|
||||
<div className={"title"}>Betang</div>
|
||||
<div className={"sub-title"}>Portal Payment</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={"search"}>
|
||||
<Input className={"form"} placeholder={"Cari Tiket Konser Sekarang !"} prefix={<SearchOutlined/>}/>
|
||||
<Input className={"form"} placeholder={"Cari Tiket Sekarang !"} prefix={<SearchOutlined/>}/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -14,7 +14,7 @@ export default function HeaderSmall({isVisible}) {
|
||||
</div>
|
||||
|
||||
<div className={"search"}>
|
||||
<Input className={"form"} placeholder={"Cari Tiket Konser Sekarang !"} prefix={<SearchOutlined/>}/>
|
||||
<Input className={"form"} placeholder={"Cari Apapun !"} prefix={<SearchOutlined/>}/>
|
||||
</div>
|
||||
<ExportedImage className={"image-export layer"} src={"/image/layer1.png"} fill={true} alt="layer" />
|
||||
|
@ -3,7 +3,7 @@ import {Input} from "antd";
|
||||
import Link from "next/link";
|
||||
import ExportedImage from "next-image-export-optimizer";
|
||||
|
||||
export default function HeaderSmallDetail({isVisible}) {
|
||||
export default function HeaderSmallDetail({isVisible,noSearch}) {
|
||||
return(
|
||||
<>
|
||||
<section className={`header-small ${isVisible ? 'hidden' : 'visible'}`}>
|
||||
@ -14,9 +14,10 @@ export default function HeaderSmallDetail({isVisible}) {
|
||||
<LeftOutlined style={{marginTop: '7px',color:'#fff'}}/>
|
||||
</Link>
|
||||
|
||||
<div className={"search"} style={{marginLeft:'50px'}}>
|
||||
<Input className={"form"} placeholder={"Cari Tiket Konser Sekarang !"} prefix={<SearchOutlined/>}/>
|
||||
</div>
|
||||
{(noSearch) ? '':<div className={"search"} style={{marginLeft:'50px'}}>
|
||||
<Input className={"form"} placeholder={"Cari Apapun !"} prefix={<SearchOutlined/>}/>
|
||||
</div>}
|
||||
|
||||
<ExportedImage className={"image-export layer"} src={"/image/layer1.png"} fill={true} alt="layer" />
|
||||
|
||||
</section>
|
69
src/component/Input/InputDate.jsx
Normal file
@ -0,0 +1,69 @@
|
||||
import {Helper} from "@/lib/Helper";
|
||||
import {DatePicker} from "antd";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
const InputDate = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
maxlength,
|
||||
required,
|
||||
setValue,
|
||||
value,
|
||||
minDate,
|
||||
maxDate,
|
||||
picker = "default",
|
||||
format = 'DD MMM YYYY',
|
||||
}) => {
|
||||
let setRequired = required
|
||||
? { required: `Data ${title} Harus di Isi` }
|
||||
: {};
|
||||
let setMaxLength = maxlength
|
||||
? {
|
||||
maxLength: {
|
||||
value: maxlength,
|
||||
message: `Maksimal ${maxlength} Karakter`,
|
||||
},
|
||||
}
|
||||
: {};
|
||||
|
||||
let validateList = { ...setRequired, ...setMaxLength };
|
||||
|
||||
const onChange = (_, dateString) => {
|
||||
setValue(name, dayjs(dateString, 'DD MMM YYYY'), { shouldValidate: true });
|
||||
};
|
||||
|
||||
const newFormat = Helper.setFormatInputDate(picker, format);
|
||||
|
||||
return (
|
||||
<div className={`form-group mb-10 ${error[name]?.message ? "error" : ""}`}>
|
||||
<div className="floating-label-content">
|
||||
<DatePicker
|
||||
{...register(name, validateList)}
|
||||
name={name}
|
||||
id={name}
|
||||
format={newFormat}
|
||||
onChange={onChange}
|
||||
// defaultValue={(defaultDate) ? dayjs(defaultDate,'YYYY-MM-DD'):null}
|
||||
minDate={minDate ? dayjs(minDate, 'YYYY-MM-DD') : null}
|
||||
maxDate={maxDate ? dayjs(maxDate, 'YYYY-MM-DD') : null}
|
||||
value={value ? dayjs(value, 'YYYY-MM-DD') : null}
|
||||
placeholder={placeholder || "Pilih Tanggal"}
|
||||
picker={picker == "default" ? undefined : picker}
|
||||
className="form-control borderInput floating-input"
|
||||
/>
|
||||
<label className="floating-label" htmlFor={name}>
|
||||
{" "}
|
||||
{title}{" "}{(required) ? <span className={"fw-7 text-danger"}>*</span>:''}
|
||||
</label>
|
||||
{error[name] && (
|
||||
<div className="error-form">{error[name]?.message}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputDate;
|
66
src/component/Input/InputDateRange.jsx
Normal file
@ -0,0 +1,66 @@
|
||||
import {Helper} from "@/lib/Helper";
|
||||
import {DatePicker, Space} from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const rangePresets = [
|
||||
{ label: 'Seminggu terakhir', value: [dayjs().add(-7, 'd'), dayjs()] },
|
||||
{ label: 'Bulan ini', value: [dayjs().startOf("month") , dayjs().endOf("month")] },
|
||||
{ label: 'Bulan lalu', value: [dayjs().startOf("month").month(dayjs().month() - 1), dayjs().endOf("month").month(dayjs().month() - 1)] },
|
||||
{label: 'Tahun ini', value: [dayjs().startOf("year"), dayjs().endOf("year")]},
|
||||
{label: 'Tahun lalu', value: [dayjs().startOf('year').year(dayjs().year() - 1), dayjs().endOf('year').year(dayjs().year() - 1)]},
|
||||
];
|
||||
|
||||
const InputDateRange = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
maxlength,
|
||||
required,
|
||||
setValue,
|
||||
format = 'DD MMM YYYY',
|
||||
picker = 'default',
|
||||
}) => {
|
||||
let setRequired = (required) ? { required: `Data ${title} Harus di Isi` } : {}
|
||||
let setMaxLength = (maxlength) ? { maxLength: { value: maxlength, message: `Maksimal ${maxlength} Karakter` } } : {}
|
||||
|
||||
let validateList = {...setRequired,...setMaxLength}
|
||||
|
||||
const onChange = (_, dateString) => {
|
||||
setValue(name, {
|
||||
startDate: dateString[0],
|
||||
endDate: dateString[1]
|
||||
}, { shouldValidate: true })
|
||||
};
|
||||
|
||||
const newFormat = Helper.setFormatInputDate(picker, format)
|
||||
|
||||
return (
|
||||
<div className={`form-group mb-10 ${(error[name]?.message) ? 'error' : ''}`} style={{marginTop: '-15px'}}>
|
||||
<div className="floating-label-content">
|
||||
<Space direction="vertical" size={0} className='w-full'>
|
||||
<label className="floating-label" style={{zIndex: '1', top: '0'}} htmlFor={name}> {title} </label>
|
||||
<RangePicker
|
||||
{...register(name, validateList)}
|
||||
name={name}
|
||||
id={name}
|
||||
presets={rangePresets}
|
||||
onChange={onChange}
|
||||
format={newFormat}
|
||||
picker={picker == 'default' ? undefined : picker}
|
||||
className="form-control borderInput floating-input"
|
||||
style={{
|
||||
display: 'flex'
|
||||
}}/>
|
||||
</Space>
|
||||
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputDateRange;
|
||||
|
50
src/component/Input/InputEmail.jsx
Normal file
@ -0,0 +1,50 @@
|
||||
const InputEmail = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
maxlength,
|
||||
required,
|
||||
}) => {
|
||||
let setRequired = (required) ? {required: "Data must be filled in"} : {}
|
||||
let setMaxLength = (maxlength) ? {maxLength: {value: maxlength, message: `Maksimal ${maxlength} Karakter`}} : {}
|
||||
let setEmail = {
|
||||
pattern: {
|
||||
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
|
||||
message: 'Format E-Mail Salah',
|
||||
}
|
||||
}
|
||||
|
||||
let validateList = {...setRequired, ...setMaxLength, ...setEmail}
|
||||
|
||||
const handleInput = (e) => {
|
||||
e.target.value = e.target.value.replace(/[^a-zA-Z0-9_!@#$-%+.=&]/g, "");
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className={`form-group mb-10 ${(error[name]?.message) ? 'error' : ''}`}>
|
||||
<div className="floating-label-content">
|
||||
<input
|
||||
type="input"
|
||||
{...register(name, validateList)}
|
||||
className="form-control borderInput floating-input"
|
||||
name={name}
|
||||
id={name}
|
||||
maxLength={maxlength ? maxlength : 250}
|
||||
placeholder={placeholder ? placeholder : `.`}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
<label className="floating-label" htmlFor={name}>
|
||||
{title}
|
||||
</label>
|
||||
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputEmail;
|
||||
|
63
src/component/Input/InputImage.jsx
Normal file
@ -0,0 +1,63 @@
|
||||
"use client"
|
||||
import {useEffect} from "react";
|
||||
|
||||
const InputImage = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
maxlength,
|
||||
required,
|
||||
}) => {
|
||||
let setRequired = (required) ? { required: "Data must be filled in" } : {}
|
||||
let setMaxLength = (maxlength) ? { maxLength: { value: maxlength, message: `Maksimal ${maxlength} Karakter` } } : {}
|
||||
|
||||
let validateList = {...setRequired,...setMaxLength}
|
||||
|
||||
useEffect(() => {
|
||||
// $('#changeImage_'+name).hide();
|
||||
// $('#imageInput_'+name).on('change', function() {
|
||||
// let inputImg = $(this);
|
||||
// if(inputImg.val().length > 0) {
|
||||
// let fileReader = new FileReader();
|
||||
// fileReader.onload = function (data) {
|
||||
// $("#imagePreview_"+name).attr('src', data.target.result);
|
||||
// }
|
||||
// fileReader.readAsDataURL(inputImg.prop('files')[0]);
|
||||
// $("#imagePreview_"+name).css('display', 'block');
|
||||
// $('#changeImage_'+name).css('display', 'block');
|
||||
|
||||
// }
|
||||
// });
|
||||
|
||||
// $('#changeImage_'+name).on('click', function() {
|
||||
// let $control = $(this);
|
||||
// $control.css('display', 'none');
|
||||
// $('#imageInput_'+name).val('');
|
||||
// let $preview = $("#imagePreview_"+name);
|
||||
// $preview.attr('src', '/img/no-image.jpg');
|
||||
// });
|
||||
}, [])
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="fs-8 mb-1">{title}</div>
|
||||
<div className="fs-10 text-muted mb-4">Image Format PNG,JPG,JPEG Max 500 Kb. Recommendation resolution is 800 x 800</div>
|
||||
<div className="image-input mb-4">
|
||||
|
||||
<input type="file" name={name} accept="image/*" id={"imageInput_"+name} />
|
||||
<div className="content-btn">
|
||||
<label htmlFor={"imageInput_"+name} className="image-button btn btn-light-primary btn-sm btn-circle btn-sm"><i className='bx bx-image-add fs-6'></i></label>
|
||||
<button type="button" id={"changeImage_"+name} className="btn btn-light-danger btn-sm btn-circle btn-sm"><i className='bx bx-trash fs-8'></i></button>
|
||||
</div>
|
||||
<img src="/img/no-image.jpg" id={"imagePreview_"+name} className="image-preview" />
|
||||
|
||||
</div>
|
||||
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputImage;
|
99
src/component/Input/InputMoney.jsx
Normal file
@ -0,0 +1,99 @@
|
||||
const InputMoney = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
maxlength,
|
||||
required,
|
||||
setReadonly,
|
||||
satuanInput,
|
||||
allowDecimal
|
||||
}) => {
|
||||
|
||||
let setRequired = (required) ? {required: `Data ${title} Harus di Isi`} : {}
|
||||
let setMaxLength = (maxlength) ? {maxLength: {value: maxlength, message: `Maksimal ${maxlength} Karakter`}} : {}
|
||||
|
||||
let validateList = {...setRequired, ...setMaxLength}
|
||||
|
||||
const handleInput = (e) => {
|
||||
// e.target.value = e.target.value.replace(/[^0-9]/g, '');
|
||||
var separator = ".";
|
||||
var a = e.target.value;
|
||||
var b = a.replace(/[^\d]/g, "");
|
||||
var c = "";
|
||||
var panjang = b.length;
|
||||
var j = 0;
|
||||
for (var i = panjang; i > 0; i--) {
|
||||
j = j + 1;
|
||||
if (((j % 3) == 1) && (j != 1)) {
|
||||
c = b.substr(i - 1, 1) + separator + c;
|
||||
} else {
|
||||
c = b.substr(i - 1, 1) + c;
|
||||
}
|
||||
}
|
||||
e.target.value = c
|
||||
};
|
||||
|
||||
const handleInputDecimal = (event) => {
|
||||
const inputField = event.target;
|
||||
let value = inputField.value;
|
||||
|
||||
// Remove any characters that are not digits or the comma
|
||||
value = value.replace(/[^\d,]/g, '');
|
||||
|
||||
// Ensure there is only one comma
|
||||
const commaIndex = value.indexOf(',');
|
||||
if (commaIndex !== -1) {
|
||||
const beforeComma = value.slice(0, commaIndex);
|
||||
const afterComma = value.slice(commaIndex + 1).replace(/,/g, ''); // Remove any additional commas
|
||||
value = beforeComma + ',' + afterComma;
|
||||
}
|
||||
|
||||
// Format the integer part with thousand separators
|
||||
const parts = value.split(',');
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, '.');
|
||||
|
||||
// Limit to two decimal places
|
||||
if (parts.length > 1) {
|
||||
parts[1] = parts[1].slice(0, 2);
|
||||
}
|
||||
|
||||
// Join the parts back together
|
||||
value = parts.join(',');
|
||||
|
||||
|
||||
event.target.value = value
|
||||
}
|
||||
|
||||
let setStyle = (satuanInput) ? {textAlign:'right',paddingRight:'40px'} :{}
|
||||
return (
|
||||
<>
|
||||
<div className={`form-group mb-10 ${(error[name]?.message) ? 'error' : ''}`}>
|
||||
<div className="floating-label-content">
|
||||
{(satuanInput) ? <div className={"satuanInput"}>{satuanInput}</div>:''}
|
||||
<input
|
||||
type="input"
|
||||
readOnly={setReadonly}
|
||||
{...register(name, validateList)}
|
||||
className="form-control borderInput floating-input"
|
||||
style={setStyle}
|
||||
name={name}
|
||||
id={name}
|
||||
maxLength={maxlength ? maxlength : 250}
|
||||
placeholder={placeholder ? placeholder : `.`}
|
||||
onInput={(allowDecimal) ? handleInputDecimal : handleInput}
|
||||
/>
|
||||
<label className="floating-label" htmlFor={name}>
|
||||
{title} {(required) ? <span className={"fw-7 text-danger"}>*</span>:''}
|
||||
</label>
|
||||
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputMoney;
|
||||
|
56
src/component/Input/InputNumber.jsx
Normal file
@ -0,0 +1,56 @@
|
||||
const InputNumber = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
maxlength,
|
||||
minlength,
|
||||
required,
|
||||
setReadonly,
|
||||
satuanInput,
|
||||
maxNominal,
|
||||
minNominal
|
||||
}) => {
|
||||
|
||||
let setRequired = (required) ? {required: `Data ${title} Harus di Isi`} : {}
|
||||
let setMaxLength = (maxlength) ? {maxLength: {value: maxlength, message: `Maksimal ${maxlength} Karakter`}} : {}
|
||||
let setMinLength = (minlength) ? {maxLength: {value: minlength, message: `Minimal ${minlength} Karakter`}} : {}
|
||||
let setMaxNominal = (maxNominal) ? {max: {value: maxNominal, message: `Maksimal ${maxNominal} ${satuanInput ?? ''}`}} : {}
|
||||
let setMinNominal = (minNominal) ? {min: {value: minNominal, message: `Minimal ${minNominal} ${satuanInput ?? ''}`}} : {}
|
||||
|
||||
let validateList = {...setRequired, ...setMaxLength, ...setMaxNominal,...setMinNominal}
|
||||
|
||||
const handleInput = (e) => {
|
||||
e.target.value = e.target.value.replace(/[^0-9]/g, '');
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className={`form-group mb-10 ${(error[name]?.message) ? 'error' : ''}`}>
|
||||
<div className="floating-label-content">
|
||||
{(satuanInput) ? <div className={"satuanInput"}>{satuanInput}</div>:''}
|
||||
<input
|
||||
type="input"
|
||||
readOnly={setReadonly}
|
||||
{...register(name, validateList)}
|
||||
className="form-control borderInput floating-input"
|
||||
name={name}
|
||||
id={name}
|
||||
maxLength={maxlength ? maxlength : 250}
|
||||
minLength={minlength ? minlength : 0}
|
||||
placeholder={placeholder ? placeholder : `.`}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
<label className="floating-label" htmlFor={name}>
|
||||
{title} {(required) ? <span className={"fw-7 text-danger"}>*</span>:''}
|
||||
</label>
|
||||
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputNumber;
|
||||
|
61
src/component/Input/InputPassword.jsx
Normal file
@ -0,0 +1,61 @@
|
||||
"use client"
|
||||
import {useRef, useState} from "react";
|
||||
import {EyeFilled, EyeInvisibleFilled} from '@ant-design/icons';
|
||||
|
||||
const InputPassword = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
maxlength,
|
||||
required,
|
||||
}) => {
|
||||
|
||||
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const inputRef = useRef(null);
|
||||
|
||||
let setRequired = (required) ? {required: `${title} Harus di Isi`} : {}
|
||||
let setMaxLength = (maxlength) ? {maxLength: {value: maxlength, message: `Maksimal ${maxlength} Karakter`}} : {}
|
||||
let validateList = {...setRequired, ...setMaxLength}
|
||||
|
||||
const handleInput = (e) => {
|
||||
e.target.value = e.target.value.replace(/[^a-zA-Z0-9_!@#$-%+=&]/g, "");
|
||||
};
|
||||
const togglePassword = () => {
|
||||
setShowPassword(prevState => !prevState);
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`form-group mb-10 ${(error[name]) ? 'error' : ''}`}>
|
||||
<div className="floating-label-content">
|
||||
<input
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
ref={inputRef}
|
||||
{...register && {...register(name, validateList)}}
|
||||
className="form-control borderInput floating-input sh-password"
|
||||
name={name}
|
||||
id={name}
|
||||
maxLength={maxlength ? maxlength : 250}
|
||||
placeholder={placeholder ? placeholder : ` `}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
<div className="icon-password" onClick={togglePassword}>
|
||||
<span className="input-group-text icon-eye">{showPassword ? <EyeFilled style={{fontSize: '20px'}}/> : <EyeInvisibleFilled style={{fontSize: '20px'}}/>} </span>
|
||||
</div>
|
||||
<label className="floating-label" htmlFor={name}>
|
||||
{title}
|
||||
</label>
|
||||
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputPassword;
|
||||
|
67
src/component/Input/InputPercentage.jsx
Normal file
@ -0,0 +1,67 @@
|
||||
import {InputNumber} from 'antd'
|
||||
|
||||
const InputPercentage = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
maxlength,
|
||||
required,
|
||||
setReadonly,
|
||||
setValue,
|
||||
val
|
||||
}) => {
|
||||
let setRequired = required
|
||||
? { required: `Data ${title} Harus di Isi` }
|
||||
: {};
|
||||
let setMaxLength = maxlength
|
||||
? {
|
||||
maxLength: {
|
||||
value: maxlength,
|
||||
message: `Maksimal ${maxlength} Karakter`,
|
||||
},
|
||||
}
|
||||
: {};
|
||||
|
||||
let validateList = { ...setRequired, ...setMaxLength };
|
||||
|
||||
const onChange = (value) => {
|
||||
setValue(name, value, {shouldValidate: true})
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`form-group mb-10 ${
|
||||
error[name]?.message ? "error" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="floating-label-content">
|
||||
<InputNumber
|
||||
min={0}
|
||||
max={100}
|
||||
formatter={(value) => value ? `${value}` : ''}
|
||||
parser={(value) => value.replace('%', '')}
|
||||
readOnly={setReadonly}
|
||||
{...register(name, validateList)}
|
||||
className="form-control borderInput floating-input"
|
||||
name={name}
|
||||
maxLength={maxlength ? maxlength : 250}
|
||||
placeholder={placeholder ? placeholder : `.`}
|
||||
onChange={onChange}
|
||||
value={val}
|
||||
/>
|
||||
<label className="floating-label" htmlFor={name}>
|
||||
{title}
|
||||
</label>
|
||||
{error[name] && (
|
||||
<div className="error-form">{error[name]?.message}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputPercentage;
|
66
src/component/Input/InputSelect.jsx
Normal file
@ -0,0 +1,66 @@
|
||||
import {Select} from 'antd';
|
||||
|
||||
const InputSelect = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
required,
|
||||
options,
|
||||
setValue,
|
||||
setReadonly,
|
||||
setDisabled,
|
||||
val,
|
||||
loading,
|
||||
withSearch = true,
|
||||
getDataOnChange
|
||||
}) => {
|
||||
let setRequired = (required) ? {required: `Data ${title} Harus di Isi`} : {}
|
||||
let validateList = {...setRequired};
|
||||
|
||||
const handleChange = (value) => {
|
||||
setValue(name, value, {shouldValidate: true})
|
||||
if (getDataOnChange) getDataOnChange(value, setValue)
|
||||
};
|
||||
// const onSearch = (value) => {
|
||||
// console.log('search:', value);
|
||||
// };
|
||||
|
||||
const filterOption = (input, option) =>
|
||||
(option?.label ?? '').toLowerCase().includes(input.toLowerCase());
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`form-group mb-10 ${error[name]?.message ? "error" : ""}`}>
|
||||
<div className="floating-label-content">
|
||||
<Select
|
||||
disabled={setReadonly || setDisabled}
|
||||
// defaultValue="lucy"
|
||||
{...register(name, validateList)}
|
||||
name={name}
|
||||
showSearch={withSearch}
|
||||
id={name}
|
||||
value={val}
|
||||
allowClear
|
||||
loading={loading}
|
||||
onChange={handleChange}
|
||||
// onSearch={onSearch}
|
||||
filterOption={filterOption}
|
||||
style={{width: '100%'}}
|
||||
placeholder={"Pilih Data"}
|
||||
className="form-control borderInput floating-input"
|
||||
options={options}
|
||||
/>
|
||||
<label className="floating-label" htmlFor={name}>
|
||||
{title} {(required) ? <span className={"fw-7 text-danger"}>*</span>:''}
|
||||
</label>
|
||||
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputSelect;
|
41
src/component/Input/InputText.jsx
Normal file
@ -0,0 +1,41 @@
|
||||
const InputText = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
maxlength,
|
||||
required,
|
||||
setReadonly
|
||||
}) => {
|
||||
let setRequired = (required) ? {required: `Data ${title} Harus di Isi`} : {}
|
||||
let setMaxLength = (maxlength) ? {maxLength: {value: maxlength, message: `Maksimal ${maxlength} Karakter`}} : {}
|
||||
|
||||
let validateList = {...setRequired, ...setMaxLength}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`form-group mb-10 ${(error[name]?.message) ? 'error' : ''}`}>
|
||||
<div className="floating-label-content">
|
||||
<input
|
||||
type="input"
|
||||
readOnly={setReadonly}
|
||||
{...register(name, validateList)}
|
||||
className="form-control borderInput floating-input"
|
||||
name={name}
|
||||
id={name}
|
||||
maxLength={maxlength ? maxlength : 250}
|
||||
placeholder={placeholder ? placeholder : `.`}
|
||||
/>
|
||||
<label className="floating-label" htmlFor={name}>
|
||||
{title} {(required) ? <span className={"fw-7 text-danger"}>*</span>:''}
|
||||
</label>
|
||||
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputText;
|
36
src/component/Input/InputTextarea.jsx
Normal file
@ -0,0 +1,36 @@
|
||||
const InputTextarea = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
maxlength,
|
||||
required,
|
||||
setReadonly,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
let setRequired = (required) ? {required: ` ${title} Harus di Isi`} : {}
|
||||
let setMaxLength = (maxlength) ? {maxLength: {value: maxlength, message: `Maksimal ${maxlength} Karakter`}} : {}
|
||||
|
||||
let validateList = {...setRequired, ...setMaxLength}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`form-group mb-10 ${(error[name]?.message) ? 'error' : ''}`}>
|
||||
<div className="floating-label-content">
|
||||
<textarea readOnly={setReadonly} style={{width: '100%'}} {...props} className={`form-control borderInput floating-input ${className}`} {...register(name, validateList)} name={name} id={name} maxLength={maxlength ? maxlength : 250} cols="30" rows="10">
|
||||
|
||||
</textarea>
|
||||
|
||||
<label className="floating-label" htmlFor={name}>
|
||||
{title} {(required) ? <span className={"fw-7 text-danger"}>*</span>:''}
|
||||
</label>
|
||||
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputTextarea;
|
49
src/component/Input/InputUsername.jsx
Normal file
@ -0,0 +1,49 @@
|
||||
const InputUsername = ({
|
||||
title,
|
||||
name,
|
||||
register,
|
||||
error,
|
||||
placeholder,
|
||||
maxlength,
|
||||
minlength,
|
||||
required,
|
||||
setReadonly
|
||||
}) => {
|
||||
let setRequired = (required) ? {required: `${title} Harus di Isi`} : {}
|
||||
let setMaxLength = (maxlength) ? {maxLength: {value: maxlength, message: `Maksimal ${maxlength} Karakter`}} : {}
|
||||
let setMinLength = (minlength) ? {minLength: {value: minlength, message: `Minimal ${minlength} Karakter`}} : {}
|
||||
|
||||
let validateList = {...setRequired, ...setMaxLength, ...setMinLength}
|
||||
|
||||
const handleInput = (e) => {
|
||||
e.target.value = e.target.value.replace(/[^a-zA-Z0-9_!@#$-%+=&]/g, "");
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div className={`form-group mb-10 ${(error[name]?.message) ? 'error' : ''}`}>
|
||||
<div className="floating-label-content">
|
||||
<input
|
||||
type="input"
|
||||
readOnly={setReadonly}
|
||||
{...register(name, validateList)}
|
||||
className="form-control borderInput floating-input"
|
||||
name={name}
|
||||
id={name}
|
||||
maxLength={maxlength ? maxlength : 250}
|
||||
minLength={minlength ? minlength : 0}
|
||||
placeholder={placeholder ? placeholder : ` `}
|
||||
onInput={handleInput}
|
||||
/>
|
||||
<label className="floating-label" htmlFor={name}>
|
||||
{title}
|
||||
</label>
|
||||
{error[name] && <div className="error-form">{error[name]?.message}</div>}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default InputUsername;
|
||||
|
27
src/component/Input/index.jsx
Normal file
@ -0,0 +1,27 @@
|
||||
import InputEmail from "./InputEmail";
|
||||
import InputImage from './InputImage';
|
||||
import InputNumber from './InputNumber';
|
||||
import InputPassword from "./InputPassword";
|
||||
import InputSelect from './InputSelect';
|
||||
import InputText from "./InputText";
|
||||
import InputTextarea from "./InputTextarea";
|
||||
import InputUsername from "./InputUsername";
|
||||
import InputDate from './InputDate';
|
||||
import InputDateRange from './InputDateRange';
|
||||
import InputPercentage from "./InputPercentage";
|
||||
|
||||
const Input = {
|
||||
Text: InputText,
|
||||
Number: InputNumber,
|
||||
Select: InputSelect,
|
||||
Username: InputUsername,
|
||||
Email: InputEmail,
|
||||
Password: InputPassword,
|
||||
Textarea: InputTextarea,
|
||||
Image: InputImage,
|
||||
DateRange: InputDateRange,
|
||||
Date: InputDate,
|
||||
Percentage: InputPercentage,
|
||||
}
|
||||
|
||||
export default Input
|
@ -1,4 +1,4 @@
|
||||
import LoadingPage from "@/app/component/LoadingPage";
|
||||
import LoadingPage from "@/component/LoadingPage";
|
||||
import {motion} from "framer-motion"
|
||||
export default function MainLayout({children}) {
|
||||
return(
|
20
src/component/TransitionContent.jsx
Normal file
@ -0,0 +1,20 @@
|
||||
|
||||
import {motion} from "framer-motion";
|
||||
|
||||
export default function TransitionContent({children}) {
|
||||
return(
|
||||
<motion.div
|
||||
className={"animate-box"}
|
||||
initial={{ opacity: 0, y: 0 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
exit={{ opacity: 0, y: 0 }}
|
||||
transition={{
|
||||
duration: 1,
|
||||
ease: "easeInOut",
|
||||
times: [0, 0.5, 1],
|
||||
loop: Infinity,
|
||||
repeatDelay: 1
|
||||
}}
|
||||
>{children}</motion.div>
|
||||
)
|
||||
}
|
37
src/lib/API.jsx
Normal file
@ -0,0 +1,37 @@
|
||||
// const baseUrlNews = process.env.NEXT_PUBLIC_API_URL_NEWS;
|
||||
const baseUrlNews = process.env.NEXT_PUBLIC_API_URL_NEWS_NEWDATA;
|
||||
|
||||
const keyNews = 'ec08743d94634489a99f938524798910'
|
||||
const key2='157a21339fd4a2433c1f23b79f63696c'
|
||||
const keyNewdata = 'pub_50761888ae4caa07368a73121b66b5bc50110'
|
||||
|
||||
export const API = {
|
||||
GET_NEWS,
|
||||
};
|
||||
|
||||
async function GET_NEWS(url) {
|
||||
try {
|
||||
const res = await fetch(baseUrlNews+url, {
|
||||
method: 'GET',
|
||||
headers:{
|
||||
"X-ACCESS-KEY" : keyNewdata
|
||||
}
|
||||
})
|
||||
|
||||
const result = await res.json()
|
||||
|
||||
return {
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
result: result
|
||||
}
|
||||
} catch (res) {
|
||||
return {
|
||||
status: 500,
|
||||
statusText: "Error API Connection ",
|
||||
result: {
|
||||
message :"Error API Connection"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
185
src/lib/Helper.jsx
Normal file
@ -0,0 +1,185 @@
|
||||
export const Helper = {
|
||||
today,
|
||||
formatDate,
|
||||
numFormatClear,
|
||||
numFormat,
|
||||
numFormatDec,
|
||||
getDifferenceDate,
|
||||
limitString
|
||||
}
|
||||
|
||||
function today() {
|
||||
var date = new Date();
|
||||
var year = date.getFullYear();
|
||||
return year + "-" + ("0" + (date.getMonth() + 1)).slice(-2) + "-" + ("0" + date.getDate()).slice(-2);
|
||||
}
|
||||
|
||||
|
||||
function formatDate(dates, type) {
|
||||
var date = new Date(dates);
|
||||
var monthNames = [
|
||||
"Januari",
|
||||
"Februari",
|
||||
"Maret",
|
||||
"April",
|
||||
"Mei",
|
||||
"Juni",
|
||||
"Juli",
|
||||
"Agustus",
|
||||
"September",
|
||||
"Oktober",
|
||||
"November",
|
||||
"Desember",
|
||||
];
|
||||
|
||||
var monthNamesSmall = [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"Mei",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Ags",
|
||||
"Sep",
|
||||
"Okt",
|
||||
"Nov",
|
||||
"Des",
|
||||
];
|
||||
|
||||
var day = date.getDate();
|
||||
var monthIndex = date.getMonth();
|
||||
var year = date.getFullYear();
|
||||
var hour = date.getHours();
|
||||
var minute = date.getMinutes();
|
||||
var sec = date.getSeconds();
|
||||
|
||||
switch (type) {
|
||||
case "d":
|
||||
return day;
|
||||
case "m":
|
||||
return monthIndex + 1;
|
||||
case "mm":
|
||||
return monthNamesSmall[monthIndex];
|
||||
case "M":
|
||||
return monthNames[monthIndex];
|
||||
case "Y":
|
||||
return year;
|
||||
case 'd-mm-Y':
|
||||
return day + ' ' + monthNamesSmall[(monthIndex)] + ' ' + year;
|
||||
case "d-m-Y":
|
||||
return day + "-" + (monthIndex + 1) + "-" + year;
|
||||
case "Y-m-d":
|
||||
return year + "-" + (monthIndex + 1) + "-" + day;
|
||||
case "d-M-Y":
|
||||
return day + " " + monthNames[monthIndex] + " " + year;
|
||||
case "d-m-Y H:i:s":
|
||||
return (
|
||||
day +
|
||||
"-" +
|
||||
(monthIndex + 1) +
|
||||
"-" +
|
||||
year +
|
||||
", " +
|
||||
hour +
|
||||
":" +
|
||||
minute +
|
||||
":" +
|
||||
sec
|
||||
);
|
||||
case "d-M-Y H:i:s":
|
||||
return (
|
||||
day +
|
||||
" " +
|
||||
monthNames[monthIndex] +
|
||||
" " +
|
||||
year +
|
||||
", " +
|
||||
hour +
|
||||
":" +
|
||||
minute +
|
||||
":" +
|
||||
sec
|
||||
);
|
||||
|
||||
case "dMYHis":
|
||||
return (
|
||||
day + monthIndex + year + hour + minute + sec
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getDifferenceDate(dateA, dateB) {
|
||||
|
||||
const date1 = new Date(dateA);
|
||||
const date2 = new Date(dateB);
|
||||
// Convert both dates to timestamps
|
||||
const timestamp1 = date1.getTime();
|
||||
const timestamp2 = date2.getTime();
|
||||
|
||||
// Calculate the difference in milliseconds
|
||||
let diffInMs = Math.abs(timestamp2 - timestamp1);
|
||||
|
||||
// Calculate days
|
||||
const days = Math.floor(diffInMs / (1000 * 60 * 60 * 24));
|
||||
diffInMs -= days * 1000 * 60 * 60 * 24;
|
||||
|
||||
// Calculate hours
|
||||
const hours = Math.floor(diffInMs / (1000 * 60 * 60));
|
||||
diffInMs -= hours * 1000 * 60 * 60;
|
||||
|
||||
// Calculate minutes
|
||||
const minutes = Math.floor(diffInMs / (1000 * 60));
|
||||
diffInMs -= minutes * 1000 * 60;
|
||||
|
||||
return `${hours} jam yang lalu`;
|
||||
}
|
||||
|
||||
function numFormatClear(data) {
|
||||
return data.replace(/\./g, "");
|
||||
}
|
||||
|
||||
function limitString(text, limit) {
|
||||
return text.length > limit ? text.substring(0, limit) + "..." : text;
|
||||
}
|
||||
|
||||
function numFormatDec(amount, decimalCount = 2, decimal = ",", thousands = ".") {
|
||||
try {
|
||||
decimalCount = Math.abs(decimalCount);
|
||||
decimalCount = isNaN(decimalCount) ? 2 : decimalCount;
|
||||
|
||||
const negativeSign = amount < 0 ? "-" : "";
|
||||
|
||||
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(decimalCount)).toString();
|
||||
let j = (i.length > 3) ? i.length % 3 : 0;
|
||||
|
||||
return negativeSign + (j ? i.substr(0, j) + thousands : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands) + (decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "");
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
function numFormat(amount, decimalCount = 0, decimal = ",", thousands = ".") {
|
||||
// try {
|
||||
// console.log(value)
|
||||
// let val = (value / 1).toFixed(0).replace(".", ",");
|
||||
// return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
|
||||
// }catch (e) {
|
||||
// console.log(e)
|
||||
// }
|
||||
|
||||
try {
|
||||
decimalCount = Math.abs(decimalCount);
|
||||
decimalCount = isNaN(decimalCount) ? 2 : decimalCount;
|
||||
|
||||
const negativeSign = amount < 0 ? "-" : "";
|
||||
|
||||
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(decimalCount)).toString();
|
||||
let j = (i.length > 3) ? i.length % 3 : 0;
|
||||
|
||||
return negativeSign + (j ? i.substr(0, j) + thousands : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands) + (decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "");
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|