Browse Source

Merge pull request 'upload 2024-02-28' (#63) from staging into master

Reviewed-on: ibnu/generic-ospro-frontend#63
pull/1/head
farhantock 10 months ago
parent
commit
82dcd6f6ee
  1. 87
      src/const/ApiConst.js
  2. 7
      src/const/en.json
  3. 7
      src/const/id.json
  4. 2
      src/containers/DefaultLayout/DefaultHeader.js
  5. 2
      src/containers/DefaultLayout/DefaultLayout.js
  6. 13
      src/routes.js
  7. 25
      src/views/Master/MasterCompany/index.js
  8. 9
      src/views/Master/MasterRoles/index.js
  9. 47
      src/views/Pages/Login/Login.js
  10. 8
      src/views/SimproV2/CreatedProyek/DialogDocument.js
  11. 12
      src/views/SimproV2/CreatedProyek/FormDocument.js
  12. 0
      src/views/SimproV2/DemoRequest/DialogForm.js
  13. 4
      src/views/SimproV2/DemoRequest/index.js
  14. 190
      src/views/SimproV2/ReferralCode/DialogForm.js
  15. 372
      src/views/SimproV2/ReferralCode/index.js
  16. 201
      src/views/SimproV2/SalesContact/DialogForm.js
  17. 374
      src/views/SimproV2/SalesContact/index.js
  18. 53
      src/views/SimproV2/Settings/Desktop.js
  19. 23
      src/views/SimproV2/Settings/Desktop.module.css
  20. 176
      src/views/SimproV2/Settings/DialogForm.js
  21. 69
      src/views/SimproV2/Settings/components/MyProfile/Head.module.css
  22. 436
      src/views/SimproV2/Settings/components/MyProfile/Index.js
  23. 563
      src/views/SimproV2/Settings/components/MyProfile/Index.module.css
  24. 65
      src/views/SimproV2/Settings/components/Plan/Column.js
  25. 114
      src/views/SimproV2/Settings/components/Plan/Column.module.css
  26. 69
      src/views/SimproV2/Settings/components/Plan/Container.js
  27. 229
      src/views/SimproV2/Settings/components/Plan/Container.module.css
  28. 226
      src/views/SimproV2/Settings/components/Plan/Container1.js
  29. 356
      src/views/SimproV2/Settings/components/Plan/Container1.module.css
  30. 3
      src/views/SimproV2/Settings/index.js

87
src/const/ApiConst.js

@ -118,44 +118,15 @@ export const TOKEN_ADW =
// export let BASE_OSPRO = "https://ospro-api.ospro.id";
// export let BASE_OSPRO = "https://project-api.ospro.id";
export let BASE_OSPRO = "http://localhost:8444/generic-ospro-backend";
// export let BASE_OSPRO = "http://103.73.125.81:8444"; // ip public adw
export let BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`;
export let BASE_SIMPRO_LUMEN_IMAGE = `${BASE_OSPRO}/assets/image`;
export let BASE_SIMPRO_LUMEN_FILE = `${BASE_OSPRO}/assets/file/project`;
export let BASE_SIMPRO_LUMEN_FILE_COMPANY = (file, company_name)=>{
export let BASE_SIMPRO_LUMEN_FILE_COMPANY = (file, company_name) => {
return `${BASE_OSPRO}/assets/${company_name}/file/project/${file}`;
}
// switch (APP_MODE) {
// case 'KIT':
// BASE_OSPRO = "https://kit-api.oslogdev.com"
// //for KIT server
// // BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`;
// // BASE_SIMPRO_LUMEN_IMAGE = `${BASE_SIMPRO_LUMEN}/assets/image`;
// // BASE_SIMPRO_LUMEN_FILE = `${BASE_SIMPRO_LUMEN}/assets/file/project`;
// break;
// case 'ADW':
// // BASE_OSPRO = "https://adw-api.ospro.id"
// BASE_OSPRO = "http://103.73.125.81:8444";
// BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`;
// BASE_SIMPRO_LUMEN_IMAGE = `${BASE_OSPRO}/assets/image`;
// BASE_SIMPRO_LUMEN_FILE = `${BASE_OSPRO}/assets/file/project`;
// break;
// case 'IU':
// BASE_OSPRO = "https://api-iu.ospro.id"
// BASE_SIMPRO_LUMEN = `${BASE_OSPRO}/api`;
// BASE_SIMPRO_LUMEN_IMAGE = `${BASE_OSPRO}/assets/image`;
// BASE_SIMPRO_LUMEN_FILE = `${BASE_OSPRO}/assets/file/project`;
// break;
// default:
// BASE_OSPRO = "https://ospro-api.ospro.id"
// }
export let BASE_SIMPRO_LUMEN_IMAGE_COMPANY = (file, company_name) => {
return `${BASE_OSPRO}/assets/${company_name}/image/${file}`;
}
export const USERROLE_ADD = `${BASE_SIMPRO}/user-role/add`;
export const USERROLE_SEARCH = `${BASE_SIMPRO}/user-role/search`;
@ -300,6 +271,19 @@ export const REFFERAL_EDIT = (id) => {
return `${BASE_SIMPRO_LUMEN}/refferal-code/update/${id}`;
};
export const TRANSACTION_ADD = `${BASE_SIMPRO_LUMEN}/product-transaction/add`;
export const TRANSACTION_SEARCH = `${BASE_SIMPRO_LUMEN}/product-transaction/search`;
export const TRANSACTION_GET_ID = (id) => {
return `${BASE_SIMPRO_LUMEN}/product-transaction/edit/${id}`;
};
export const TRANSACTION_EDIT = (id) => {
return `${BASE_SIMPRO_LUMEN}/product-transaction/update/${id}`;
};
export const STORAGE_LIMIT_INFORMATION = (company_name) => {
return `${BASE_SIMPRO_LUMEN}/information-storage/${company_name}`;
};
export const ABSENSI_ADD = `${BASE_SIMPRO_LUMEN}/permit/add`;
export const ABSENSI_SEARCH = `${BASE_SIMPRO_LUMEN}/permit/search`;
export const ABSENSI_EDIT = (id) => {
@ -733,12 +717,6 @@ export const ASSIGN_HR_PROJECT_DELETE = (id, company_id) => {
};
export const ASSIGN_HR_PROJECT_LIST = `${BASE_SIMPRO_LUMEN}/user-to-proyek/list`;
export const IMAGE_GET_BY_ID = (id, category) => {
return `${BASE_SIMPRO_LUMEN}/image/${id}/${category}`;
};
export const IMAGE_SEARCH = `${BASE_SIMPRO_LUMEN}/image/search`;
export const OSPRO_BASE_IMAGE = `${BASE_OSPRO}/api/assets/image`;
export const DASHBOARD_COST_PLANNING_ACTUAL = `${BASE_SIMPRO_LUMEN}/dashboard/cost-planning-actual`;
export const DASHBOARD_PERSENTASE_PROGRESS_PROYEK = `${BASE_SIMPRO_LUMEN}/dashboard/percentage-planning-actual`;
export const DASHBOARD_REPORT_POINTS = `${BASE_SIMPRO_LUMEN}/report-activity/search-point`;
@ -798,6 +776,11 @@ export const HIERARCHY_FTTH_COUNT_TREE = (id) => {
export const WAYPOINT_SEARCH = `${BASE_SIMPRO_LUMEN}/waypoint/search`;
export const IMAGE_GET_BY_ID = (id, category) => {
return `${BASE_SIMPRO_LUMEN}/image/${id}/${category}`;
};
export const IMAGE_SEARCH = `${BASE_SIMPRO_LUMEN}/image/search`;
export const OSPRO_BASE_IMAGE = `${BASE_OSPRO}/api/assets/image`;
export const IMAGE_UPLOAD = `${BASE_SIMPRO_LUMEN}/image/upload`;
export const IMAGE_MULTIPLE_UPLOAD = `${BASE_SIMPRO_LUMEN}/image/multiple-upload`;
export const IMAGE_MULTIPLE_DELETE = (id, category, company_id) => {
@ -835,8 +818,6 @@ export const MENU_COMPANY_DELETE = (id) => {
return `${BASE_SIMPRO_LUMEN}/menu-company/delete/${id}`;
};
export const DEMO_MANAGEMENT_ADD = `${BASE_SIMPRO_LUMEN}/demo-management/add`;
export const DEMO_MANAGEMENT_SEARCH = `${BASE_SIMPRO_LUMEN}/demo-management/search`;
export const DEMO_MANAGEMENT_EDIT = (id) => {
@ -849,3 +830,27 @@ export const DEMO_MANAGEMENT_DELETE = (id) => {
return `${BASE_SIMPRO_LUMEN}/demo-management/delete/${id}`;
};
export const DEMO_MANAGEMENT_LIST = `${BASE_SIMPRO_LUMEN}/demo-management/list`;
export const REFERRAL_CODE_ADD = `${BASE_SIMPRO_LUMEN}/refferal-code/add`;
export const REFERRAL_CODE_SEARCH = `${BASE_SIMPRO_LUMEN}/refferal-code/search`;
export const REFERRAL_CODE_EDIT = (id) => {
return `${BASE_SIMPRO_LUMEN}/refferal-code/update/${id}`;
};
export const REFERRAL_CODE_GET_ID = (id) => {
return `${BASE_SIMPRO_LUMEN}/refferal-code/edit/${id}`;
};
export const REFERRAL_CODE_DELETE = (id) => {
return `${BASE_SIMPRO_LUMEN}/refferal-code/delete/${id}`;
};
export const SALES_CONTACT_ADD = `${BASE_SIMPRO_LUMEN}/sales-contact/add`;
export const SALES_CONTACT_SEARCH = `${BASE_SIMPRO_LUMEN}/sales-contact/search`;
export const SALES_CONTACT_EDIT = (id) => {
return `${BASE_SIMPRO_LUMEN}/sales-contact/update/${id}`;
};
export const SALES_CONTACT_GET_ID = (id) => {
return `${BASE_SIMPRO_LUMEN}/sales-contact/edit/${id}`;
};
export const SALES_CONTACT_DELETE = (id) => {
return `${BASE_SIMPRO_LUMEN}/sales-contact/delete/${id}`;
};

7
src/const/en.json

@ -1,6 +1,8 @@
{
"3days": "3 Days Ago",
"7days": "7 Days Ago",
"amount": "Amount",
"allocation": "Allocation",
"action": "Action",
"add": "Add",
"address": "Address",
@ -16,6 +18,8 @@
"cancel": "Cancel",
"close": "Close",
"color": "Color",
"code": "Code",
"discount": "Discount",
"date": "Date",
"dateSend": "Send Date",
"dateAbsent": "Absent Date",
@ -37,6 +41,7 @@
"demoAdd": "Add Demo",
"employeeType": "Employee Type",
"edit": "Edit",
"exp": "Expire",
"export": "Export",
"exportExcel": "Export Excel",
"exportPdf": "Export Pdf",
@ -54,6 +59,8 @@
"inputDescription": "Input Description",
"inputParentMenu": "Select Parent Menu",
"inputAliasMenu": "Input Menu Alias",
"inputAmount": "Input Amount",
"inputCode": "Input Code",
"inputOrder": "Input Order",
"inputUrl": "Input URL",
"inputMsg": "Input Message",

7
src/const/id.json

@ -1,6 +1,8 @@
{
"3days": "3 Hari Yang lalu",
"7days": "7 Hari Yang lalu",
"amount": "Jumlah",
"allocation": "Kuota",
"action": "Aksi",
"add": "Tambah",
"address": "Alamat",
@ -16,6 +18,8 @@
"cancel": "Batal",
"close": "Tutup",
"color": "Warna",
"code": "Kode",
"discount": "Diskon",
"date": "Tanggal",
"dateSend": "Tanggal Kirim",
"dateAbsent": "Tanggal Absen",
@ -36,6 +40,7 @@
"divisionAdd": "Tambah Divisi",
"demoAdd": "Tambah Demo",
"edit": "Ubah",
"exp": "Batas Waktu",
"export": "Ekspor",
"exportExcel": "Ekspor Excel",
"exportPdf": "Ekspor Pdf",
@ -69,6 +74,8 @@
"inputNik": "Masukan NIK (KTP)",
"inputMessage": "Masukan Pesan",
"inputRole": "Masukan Peran",
"inputAmount": "Masukan Jumlah",
"inputCode": "Masukan Kode",
"image": "Gambar",
"imageCheck": "Lihat Selfie Presensi",
"locIn": "Lokasi Masuk",

2
src/containers/DefaultLayout/DefaultHeader.js

@ -216,7 +216,7 @@ class DefaultHeader extends Component {
getLogo = () => {
return (
<div style={{ width: '10%', display: 'flex', justifyContent: 'center' }}>
<div style={{ width: '10%', display: 'flex', justifyContent: 'center', paddingLeft:'10px' }}>
<img
style={{ width: '100%', height: '100%' }}
src={this.getLogoHeaderContent()}

2
src/containers/DefaultLayout/DefaultLayout.js

@ -111,8 +111,6 @@ class DefaultLayout extends Component {
default:
faviconElement.type = 'image/png';
}
console.log('faviconElement.type', faviconElement.type);
console.log('faviconContent', faviconContent);
faviconElement.href = faviconContent || `${process.env.PUBLIC_URL}/OSPRO.ico`;

13
src/routes.js

@ -54,9 +54,11 @@ const DashboardCustomer = React.lazy(() => import('./views/Dashboard/DashboardCu
const DashboardProject = React.lazy(() => import('./views/Dashboard/DashboardProject'));
const DashboardProjectCarousell = React.lazy(() => import('./views/Dashboard/DashboardProjectCarousell'));
const MapMonitoring = React.lazy(() => import('./views/MapMonitoring'));
const Settings = React.lazy(() => import('./views/SimproV2/Settings'));
const Settings = React.lazy(() => import('./views/SimproV2/Settings/Desktop'));
const CompanyManagement = React.lazy(() => import('./views/Master/MasterCompany'))
const DemoManagement = React.lazy(() => import('./views/SimproV2/Demo'))
const DemoRequest = React.lazy(() => import('./views/SimproV2/DemoRequest'))
const ReferralCode = React.lazy(() => import('./views/SimproV2/ReferralCode'))
const SalesContact = React.lazy(() => import('./views/SimproV2/SalesContact'))
const routes = [
{ path: '/', exact: true, name: 'Home' },
{ path: '/dashboard', name: 'DashboardBOD', component: DashboardBOD },
@ -119,8 +121,11 @@ const routes = [
{ path: '/map-monitoring', exact: true, name: 'Map Monitoring', component: MapMonitoring },
// { path: '/dashboard-project/:ID/:GANTTID', exact: true, name: 'Dashboard Project', component: DashboardProject },
{ path: '/settings', exact: true, name: 'Settings', component: Settings },
{ path: '/company-management', exact: true, name: 'Company Management', component: CompanyManagement },
{ path: '/demo-management', exact: true, name: 'Demo Management', component: DemoManagement },
{ path: '/register-management', exact: true, name: 'Register Management', component: CompanyManagement },
{ path: '/demo-request', exact: true, name: 'Request Demo', component: DemoRequest },
{ path: '/referral-code-management', exact: true, name: 'Referral Code Management', component: ReferralCode },
{ path: '/sales-contact', exact: true, name: 'Sales Contact', component: SalesContact },
];
export default routes;

25
src/views/Master/MasterCompany/index.js

@ -20,7 +20,11 @@ const config = {
const MasterCompany = ({ params }) => {
const token = localStorage.getItem("token")
const company_id = localStorage.getItem("company_id")
let company_id = '';
const role = window.localStorage.getItem('role_name');
if(role != 'Super Admin') {
company_id = localStorage.getItem("company_id");
}
const HEADER = {
headers: {
"Content-Type": "application/json",
@ -53,7 +57,10 @@ const MasterCompany = ({ params }) => {
const [loading, setLoading] = useState(true);
const pageName = params.name;
const { t } = useTranslation();
const configApp = JSON.parse(window.localStorage.getItem('configApp'));
let configApp = '';
if (role !== 'Super Admin') {
configApp = JSON.parse(window.localStorage.getItem('configApp'));
}
useEffect(() => {
setLoading(true)
getDataCompany()
@ -354,7 +361,9 @@ const MasterCompany = ({ params }) => {
formData.append('ref_id', id);
formData.append('category', 'company_logo_header');
formData.append('files', data);
if(role != 'Super Admin') {
formData.append('company_name',configApp.company_name);
}
await axios
.post(IMAGE_UPLOAD, formData, HEADER_MULTIPART)
@ -368,7 +377,9 @@ const MasterCompany = ({ params }) => {
formData.append('ref_id', id);
formData.append('category', 'company_logo_login');
formData.append('files', data);
if(role != 'Super Admin') {
formData.append('company_name',configApp.company_name);
}
await axios
.post(IMAGE_UPLOAD, formData, HEADER_MULTIPART)
@ -382,7 +393,9 @@ const MasterCompany = ({ params }) => {
formData.append('ref_id', id);
formData.append('category', 'company_favicon');
formData.append('files', data);
if(role != 'Super Admin') {
formData.append('company_name',configApp.company_name);
}
await axios
.post(IMAGE_UPLOAD, formData, HEADER_MULTIPART)
@ -402,7 +415,7 @@ const MasterCompany = ({ params }) => {
// Delete Image Function
const deleteImageHeader = async (id) => {
const URL = IMAGE_DELETE(id, 'company_logo_header', company_id);
const URL = IMAGE_DELETE(id, 'company_logo_header', company_id != '' ? company_id : 'undifined');
await axios
.delete(URL, HEADER)
.then(res => res)
@ -411,7 +424,7 @@ const MasterCompany = ({ params }) => {
};
const deleteImageLogin = async (id) => {
const URL = IMAGE_DELETE(id, 'company_logo_login', company_id);
const URL = IMAGE_DELETE(id, 'company_logo_login', company_id != '' ? company_id : 'undifined');
await axios
.delete(URL, HEADER)
.then(res => res)
@ -420,7 +433,7 @@ const MasterCompany = ({ params }) => {
};
const deleteImageFavicon = async (id) => {
const URL = IMAGE_DELETE(id, 'company_favicon', company_id);
const URL = IMAGE_DELETE(id, 'company_favicon', company_id != '' ? company_id : 'undifined');
await axios
.delete(URL, HEADER)
.then(res => res)
@ -429,7 +442,7 @@ const MasterCompany = ({ params }) => {
};
const deleteImageSlider = async (id) => {
const URL = IMAGE_MULTIPLE_DELETE(id, 'company_slider_login', company_id);
const URL = IMAGE_MULTIPLE_DELETE(id, 'company_slider_login', company_id != '' ? company_id : 'undifined');
await axios
.delete(URL, HEADER)
.then(res => res)

9
src/views/Master/MasterRoles/index.js

@ -331,10 +331,15 @@ class index extends Component {
let promises = []
let result = []
dataArray.map((val, index) => {
if (val.checked === true) {
if (val.read === true) {
const formData = {
menu_id: val.menu_id,
role_id: val.roles_id
role_id: val.roles_id,
create: val.create,
read: val.read,
update: val.update,
delete: val.delete
}
promises.push(axios.post(ROLEMENU_ADD, formData, this.state.config)
.then(res => result.push(res)))

47
src/views/Pages/Login/Login.js

@ -35,7 +35,7 @@ const settings = {
arrows: false,
autoplay: true,
slidesToShow: 1,
slidesToScroll: 1
slidesToScroll: 1,
};
class Login extends Component {
@ -320,22 +320,22 @@ class Login extends Component {
}
getLoginLogo = () => {
return <div style={{ textAlign: 'center' }}><img style={{ width: '100%' }} src={logo_ospro} /></div>
return <div style={{ textAlign: 'left', paddingBottom:'15px' }}><img style={{ width: '35%' }} src={logo_ospro} /></div>
}
getLoginSlider = () => {
return <Slider {...settings} >
<div>
<img src={require('../../../assets/img/login/slide1.jpg')} className="img-avatar" />
<img src={require('../../../assets/img/login/slide1.jpg')} style={{display:'block', maxWidth:'100%', height:'auto'}}/>
</div>
<div>
<img src={require('../../../assets/img/login/slide2.jpg')} className="img-avatar" />
<img src={require('../../../assets/img/login/slide2.jpg')} style={{display:'block', maxWidth:'100%', height:'auto'}} />
</div>
<div>
<img src={require('../../../assets/img/login/slide3.jpg')} className="img-avatar" />
<img src={require('../../../assets/img/login/slide3.jpg')} style={{display:'block', maxWidth:'100%', height:'auto'}} />
</div>
<div>
<img src={require('../../../assets/img/login/slide4.jpg')} className="img-avatar" />
<img src={require('../../../assets/img/login/slide4.jpg')} style={{display:'block', maxWidth:'100%', height:'auto'}} />
</div>
</Slider>
}
@ -362,16 +362,20 @@ class Login extends Component {
<Col md="7">
{this.getLoginSlider()}
</Col>
<Col md="5">
<Col md="5" style={{display:'flex', alignItems:'stretch'}}>
<div style={{
boxShadow: '1px 1px 11px 1px rgba(221,211,211,0.75)'
boxShadow: '1px 1px 11px 1px rgba(221,211,211,0.75)',
}}>
<CardGroup>
<Card className="p-4">
<CardGroup style={{height:'100%', display:'flex', alignContent:'center'}}>
<Card className="p-4" style={{border:'solid #fff'}}>
<CardBody>
<Form onSubmit={this.submitForm}>
{this.getLoginLogo()}
<p className="text-muted">Sign In to your account</p>
<div>
<h1 className="mb-1" style={{coror:'#232323'}}>Welcome to OSPRO!</h1>
<p style={{fontSize:'16px', color:'#898989'}}>Please sign-in to your account and start the adventure</p>
</div>
<InputGroup className="mb-3">
<InputGroupAddon addonType="prepend">
<InputGroupText>
@ -389,7 +393,8 @@ class Login extends Component {
}}
/>
</InputGroup>
<InputGroup className="mb-4">
<InputGroup >
<InputGroupAddon addonType="prepend">
<InputGroupText>
<i className="icon-lock"></i>
@ -413,11 +418,17 @@ class Login extends Component {
</InputGroupAddon>
<span className="password__show" ></span>
</InputGroup>
<Row>
<Col xs="8">
<Row className="mb-2" style={{display:'flex', alignItems:'center'}}>
<Col xs="7">
<Checkbox checked={this.state.remember} onChange={this.onChecked}>Remember me (7 days)</Checkbox>
</Col>
<Col xs="4">
<Col className="text-right ">
<Button color="link" className="px-0">Forgot password?</Button>
</Col>
</Row>
<Row>
<Col className="text-right ">
{this.state.loader ? (
<Spin indicator={antIcon} />
) : (
@ -425,11 +436,7 @@ class Login extends Component {
)}
</Col>
</Row>
<Row>
<Col className="text-right mt-5">
<Button color="link" className="px-0">Forgot password?</Button>
</Col>
</Row>
</Form>
</CardBody>
</Card>

8
src/views/SimproV2/CreatedProyek/DialogDocument.js

@ -12,6 +12,7 @@ import DialogRequest from './FormDocument';
import DialogRequestFolder from './FormFolderDocument';
const DialogDocument = ({ openDialog, closeDialog, toggleDialog, idTask, proyekName }) => {
const token = localStorage.getItem("token")
const role = window.localStorage.getItem('role_name');
const HEADER = {
headers: {
"Content-Type": "application/json",
@ -99,8 +100,11 @@ const DialogDocument = ({ openDialog, closeDialog, toggleDialog, idTask, proyekN
}
const handleShow = (file) => {
const configApp = JSON.parse(window.localStorage.getItem('configApp'));
const urlShow = `${BASE_SIMPRO_LUMEN_FILE_COMPANY(file, configApp.company_name)}`
let configApp = '';
if (role !== 'Super Admin') {
configApp = JSON.parse(window.localStorage.getItem('configApp'));
}
const urlShow = `${BASE_SIMPRO_LUMEN_FILE_COMPANY(file, configApp != '' ? configApp.company_name : 'undifined')}`
window.open(urlShow);
}

12
src/views/SimproV2/CreatedProyek/FormDocument.js

@ -7,7 +7,8 @@ import 'antd/dist/antd.css';
import { NotificationManager } from 'react-notifications';
const DialogRequest = ({ openDialog, closeDialog, toggleDialog, idTask, parentIdNewFolder }) => {
const token = localStorage.getItem("token")
const token = localStorage.getItem("token");
const role = window.localStorage.getItem('role_name');
const HEADER = {
headers: {
"Content-Type": "application/json",
@ -33,12 +34,13 @@ const DialogRequest = ({ openDialog, closeDialog, toggleDialog, idTask, parentId
}
const uploadDokumen = async () => {
const configApp = JSON.parse(window.localStorage.getItem('configApp'));
let configApp = '';
const formData = new FormData;
formData.append('dokumen', file, file.name);
if (role !== 'Super Admin') {
configApp = JSON.parse(window.localStorage.getItem('configApp'));
formData.append('company_name',configApp.company_name);
}
formData.append('dokumen', file, file.name);
if (parentIdNewFolder > 0) {
formData.append('ref_id', parentIdNewFolder); // folder_id
formData.append('type_dokumen', 'project-document-in-folder');

0
src/views/SimproV2/Demo/DialogForm.js → src/views/SimproV2/DemoRequest/DialogForm.js

4
src/views/SimproV2/Demo/index.js → src/views/SimproV2/DemoRequest/index.js

@ -202,7 +202,7 @@ const ProjectType = ({ params, ...props }) => {
if (type === "save") {
saveDemo(data);
} else if (type === "edit") {
editMaterialR(data);
editDemo(data);
}
setDataEdit([])
setOpenDialog(false)
@ -221,7 +221,7 @@ const ProjectType = ({ params, ...props }) => {
}
}
const editMaterialR = async (data) => {
const editDemo = async (data) => {
let urlEdit = DEMO_MANAGEMENT_EDIT(data.id)
const formData = data
const result = await axios.put(urlEdit, formData, HEADER)

190
src/views/SimproV2/ReferralCode/DialogForm.js

@ -0,0 +1,190 @@
import React, { useEffect, useState } from 'react'
import {
Modal, ModalHeader, ModalBody, ModalFooter,
Button, Form, FormGroup, Label, Input, Col, Row
} from 'reactstrap';
import { Select, DatePicker } from 'antd';
import 'antd/dist/antd.css';
import { useTranslation } from 'react-i18next';
import "rc-color-picker/assets/index.css";
import moment from 'moment';
import { formatNumber } from "../../../const/CustomFunc";
const { Option } = Select
const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdit }) => {
const [id, setId] = useState(0)
const [code, setCode] = useState('')
const [amount, setAmount] = useState(0)
const [description, setDescription] = useState('')
const [exp, setExp] = useState('')
const [type, setType] = useState('')
const [allocation, setAllocation] = useState(0)
const { t } = useTranslation()
useEffect(() => {
console.log('dataEdit', dataEdit);
if (typeDialog === "Edit") {
setId(dataEdit.id)
setCode(dataEdit.code)
setAmount(dataEdit.amount)
setDescription(dataEdit.description)
setExp(dataEdit.exp)
setType(dataEdit.type)
} else {
handleClear()
}
}, [dataEdit, openDialog])
const validation = () => {
if (!code || code === "") {
alert("Code cannot be empty!");
return true;
}
}
const handleSave = () => {
let data = '';
const err = validation();
if (!err) {
if (typeDialog === "Save") {
data = {
code,
amount,
description,
exp,
type,
allocation
}
console.log('data', data);
closeDialog('save', data);
} else {
data = {
id,
code,
amount,
description,
exp,
type,
allocation
}
console.log('data', data);
closeDialog('edit', data);
}
handleClear()
}
}
const handleCancel = () => {
closeDialog('cancel', 'none')
handleClear()
}
const handleClear = () => {
setId(0)
setCode('')
setAmount('')
setDescription('')
setExp('')
}
const renderForm = () => {
return (
<Form>
<Row>
<Col md={12}>
<span style={{ color: "red" }}>*</span> Wajib diisi.
</Col>
</Row>
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('code')} {t('discount')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={code}
onChange={(e) => setCode(e.target.value)}
placeholder={t('inputCode')}
/>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('amount')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder={t('inputAmount')}
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize" style={{ fontWeight: "bold" }}>
{t('exp')}<span style={{ color: "red" }}>*</span>
</Label>
<DatePicker
format={"DD-MM-YYYY HH:mm"}
style={{ width: "100%" }}
value={exp ? moment(exp) : exp}
onChange={(date, dateString) => setExp(date)}
showTime={{ defaultValue: moment('00:00:00', 'HH:mm:ss') }}
/>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('allocation')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="number"
value={allocation}
onChange={(e) => setAllocation(e.target.value)}
placeholder={t('input')}
/>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('type')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={type}
onChange={(e) => setType(e.target.value)}
placeholder={t('inputType')}
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col md={12}>
<FormGroup>
<Label className="capitalize">{t('description')}</Label>
<Input row="4" type="textarea" value={description} onChange={(e) => setDescription(e.target.value)} placeholder={t('inputDescription')} />
</FormGroup>
</Col>
</Row>
</Form>
)
}
return (
<>
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>{typeDialog == "Save" ? `Add` : "Edit"} {t('Demo')}</ModalHeader>
<ModalBody>
{renderForm()}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>{typeDialog}</Button>{' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>{t('cancel')}</Button>
</ModalFooter>
</Modal>
</>
)
}
export default DialogForm;

372
src/views/SimproV2/ReferralCode/index.js

@ -0,0 +1,372 @@
import * as XLSX from 'xlsx';
import DialogForm from './DialogForm';
import React, { useState, useEffect } from 'react';
import SweetAlert from 'react-bootstrap-sweetalert';
import axios from "../../../const/interceptorApi"
import { Card, CardBody, CardHeader, Col, Row, Input, Table } from 'reactstrap';
import { REFERRAL_CODE_EDIT, REFERRAL_CODE_SEARCH, REFERRAL_CODE_ADD, REFERRAL_CODE_DELETE } from '../../../const/ApiConst';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Spin, Button, Tooltip } from 'antd';
import { useTranslation } from 'react-i18next';
import moment from 'moment';
import toRupiah from '@develoka/angka-rupiah-js';
const ProjectType = ({ params, ...props }) => {
let role_id = 0, user_id = 0, isLogin = false, token = '', company_id = 0, all_project = null, role_name = '', hierarchy = [], user_name = '';
if (props && props.role_id && props.user_id) {
role_id = props.role_id;
user_id = props.user_id;
token = props.token;
isLogin = props.isLogin;
company_id = props.company_id;
all_project = props.all_project;
role_name = props.role_name;
isLogin = props.isLogin;
hierarchy = props.hierarchy;
user_name = props.user_name;
}
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const pageName = params.name;
const [alertDelete, setAlertDelete] = useState(false)
const [allDataMenu, setAllDataMenu] = useState([])
const [clickOpenModal, setClickOpenModal] = useState(false)
const [currentPage, setCurrentPage] = useState(1)
const [dataEdit, setDataEdit] = useState([])
const [dataExport, setDataExport] = useState([])
const [dataTable, setDatatable] = useState([])
const [idDelete, setIdDelete] = useState(0)
const [openDialog, setOpenDialog] = useState(false)
const [rowsPerPage, setRowsPerPage] = useState(10)
const [search, setSearch] = useState("")
const [totalPage, setTotalPage] = useState(0)
const [typeDialog, setTypeDialog] = useState('Save')
const [dataDemo, setDataDemo] = useState([])
const [listCompany, setListCompany] = useState([])
const [loading, setLoading] = useState(true);
const { t } = useTranslation()
const column = [
{ name: t('code') },
{ name: t('type') },
{ name: t('amount') },
{ name: t('exp') },
{ name: t('allocation') },
{ name: t('description') },
].filter(column => column && column.name);
useEffect(() => {
getReferralCode();
}, [currentPage, rowsPerPage, search])
useEffect(() => {
const cekData = dataExport || []
if (cekData.length > 0) {
exportExcel()
}
}, [dataExport])
const getReferralCode = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = currentPage * rowsPerPage - rowsPerPage;
}
const payload = {
group_column: {
"operator": "AND",
"group_operator": "OR",
"where": [
{
"name": "name",
"logic_operator": "~*",
"value": search,
}
]
},
columns: [],
"orders": {
"ascending": true,
"columns": [
'id'
]
},
"paging": {
"length": rowsPerPage,
"start": start
},
'joins': []
}
const result = await axios
.post(REFERRAL_CODE_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
setDatatable(result.data.data);
setTotalPage(result.data.totalRecord);
setLoading(false)
} else {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
setLoading(false)
}
}
const handleExportExcel = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = (currentPage * rowsPerPage) - rowsPerPage
}
const payload = {
group_column: {
"operator": "AND",
"group_operator": "OR",
"where": [
{
"name": "name",
"logic_operator": "~*",
"value": search,
}
]
},
"columns": [],
"orders": {
"ascending": true,
"columns": [
'id'
]
},
"paging": {
"length": rowsPerPage,
"start": start
},
'joins': []
}
const result = await axios
.post(REFERRAL_CODE_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let resData = result.data.data;
const excelData = [];
resData.map((val, index) => {
let dataRow = {};
dataRow["Kode"] = val.code;
dataRow["Jumlah"] = val.amount;
dataRow["Kuota"] = val.allocation;
dataRow["Kadaluarsa"] = val.exp;
dataRow["Deskripsi"] = val.deskription;
excelData.push(dataRow)
})
await setDataExport(excelData)
} else {
NotificationManager.error('Gagal Export Data!!', 'Failed');
}
}
const exportExcel = () => {
const dataExcel = dataExport || [];
const fileName = `Data ${pageName}.xlsx`;
const ws = XLSX.utils.json_to_sheet(dataExcel);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`);
XLSX.writeFile(wb, fileName);
setDataExport([])
}
const handleSearch = e => {
const value = e.target.value
setSearch(value);
setCurrentPage(1)
};
const handleOpenDialog = (type) => {
setOpenDialog(true)
setTypeDialog(type)
}
const handleEdit = (data) => {
setDataEdit(data)
handleOpenDialog('Edit');
}
const handleDelete = async (id) => {
await setAlertDelete(true)
await setIdDelete(id)
}
const handleCloseDialog = (type, data) => {
if (type === "save") {
saveReferralCode(data);
} else if (type === "edit") {
editReferralCode(data);
}
setDataEdit([])
setOpenDialog(false)
}
const saveReferralCode = async (data) => {
const formData = data
const result = await axios.post(REFERRAL_CODE_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getReferralCode()
NotificationManager.success(`Data berhasil ditambahkan`, 'Success!!');
} else {
NotificationManager.error(`Data gagal ditambahkan`, 'Failed!!');
}
}
const editReferralCode = async (data) => {
let urlEdit = REFERRAL_CODE_EDIT(data.id)
const formData = data
const result = await axios.put(urlEdit, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getReferralCode();
NotificationManager.success(`Data berhasil diubah`, 'Success!!');
} else {
NotificationManager.error(`Data gagal diubah`, `Failed!!`);
}
}
const toggleAddDialog = () => {
setOpenDialog(!openDialog)
}
const onConfirmDelete = async () => {
let url = REFERRAL_CODE_DELETE(idDelete);
const result = await axios.delete(url, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getReferralCode()
setIdDelete(0)
setAlertDelete(false)
NotificationManager.success(`Data berhasil dihapus!`, 'Success!!');
} else {
setIdDelete(0)
setAlertDelete(false)
NotificationManager.error(`Data gagal dihapus!}`, 'Failed!!');
}
}
const cancelDelete = () => {
setAlertDelete(false)
setIdDelete(0)
}
const onShowSizeChange = (current, pageSize) => {
setRowsPerPage(pageSize)
}
const onPagination = (current, pageSize) => {
setCurrentPage(current)
}
const dataNotAvailable = () => {
if (dataTable.length === 0) {
return (
<tr>
<td align="center" colSpan="7">{t('noData')}</td>
</tr>
)
}
}
return (
<div>
<NotificationContainer />
<SweetAlert
show={alertDelete}
warning
showCancel
confirmBtnText="Delete"
confirmBtnBsStyle="danger"
title={t('deleteConfirm')}
onConfirm={onConfirmDelete}
onCancel={cancelDelete}
focusCancelBtn
>
{t('deleteMsg')}
</SweetAlert>
<DialogForm
openDialog={openDialog}
closeDialog={handleCloseDialog}
toggleDialog={() => toggleAddDialog}
typeDialog={typeDialog}
dataEdit={dataEdit}
clickOpenModal={clickOpenModal}
dataParent={allDataMenu}
/>
<Card>
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}>
<h4 className="capitalize">{pageName}</h4>
<Row>
<Col>
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={t('search')} />
</Col>
<Col>
<Tooltip title={t('demoAdd')}>
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button>
</Tooltip>
<Tooltip title={t('exportExcel')}>
<Button style={{ marginLeft: "5px" }} onClick={() => handleExportExcel()}><i className="fa fa-print"></i></Button>
</Tooltip>
</Col>
</Row>
</CardHeader>
<CardBody>
<Spin tip="Loading..." spinning={loading}>
<Table responsive striped hover>
<thead>
<tr>
<th>Aksi</th>
{column.map((i, index) => {
return (
<th key={index} scope="row">{i.name}</th>
)
})}
</tr>
</thead>
<tbody>
{dataNotAvailable()}
{dataTable.map((n, index) => {
return (
<tr key={n.id}>
<td className='nowrap'>
<Tooltip title={t('delete')}>
<i id="TooltipDelete" className="fa fa-trash" style={{ color: 'red', marginRight: 10, cursor: "pointer" }} onClick={() => handleDelete(n.id)}></i>
</Tooltip>
<Tooltip title={t('edit')}>
<i id="TooltipEdit" className="fa fa-edit" style={{ color: 'green', cursor: "pointer" }} onClick={() => handleEdit(n)}></i>
</Tooltip>
</td>
<td>{n.code}</td>
<td>{n.type}</td>
<td>{toRupiah(n.amount)}</td>
<td>{n?.exp ? moment(n.exp).format('DD-MM-YYYY HH:mm') : "-"}</td>
<td>{n.allocation ? n.allocation : "-"}</td>
<td>{n.description ? n.description : "-"}</td>
</tr>
)
})}
</tbody>
</Table>
</Spin>
</CardBody>
</Card>
</div>
)
}
export default ProjectType;

201
src/views/SimproV2/SalesContact/DialogForm.js

@ -0,0 +1,201 @@
import React, { useEffect, useState } from 'react'
import {
Modal, ModalHeader, ModalBody, ModalFooter,
Button, Form, FormGroup, Label, Input, Col, Row
} from 'reactstrap';
import { Select } from 'antd';
import 'antd/dist/antd.css';
import { useTranslation } from 'react-i18next';
import "rc-color-picker/assets/index.css";
const { Option } = Select
const DialogForm = ({ openDialog, closeDialog, toggleDialog, typeDialog, dataEdit }) => {
const [id, setId] = useState(0)
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [message, setMessage] = useState('')
const [phoneNumber, setPhoneNumber] = useState('')
const [role, setRole] = useState(null)
const [status, setStatus] = useState('')
const { t } = useTranslation()
useEffect(() => {
if (typeDialog === "Edit") {
setId(dataEdit.id)
setName(dataEdit.name)
setEmail(dataEdit.email)
setMessage(dataEdit.message)
setPhoneNumber(dataEdit.number_phone)
setStatus(dataEdit.status)
setRole(dataEdit.role)
} else {
setId(0)
setName('')
setEmail('')
setMessage('')
setStatus('')
setRole('')
setPhoneNumber('')
}
}, [dataEdit, openDialog])
const validation = () => {
if (!name || name === "") {
alert("Name cannot be empty!");
return true;
}
}
const handleSave = () => {
let data = '';
const err = validation();
if (!err) {
if (typeDialog === "Save") {
data = {
name,
email,
message,
number_phone: phoneNumber,
role,
status
}
closeDialog('save', data);
} else {
data = {
id,
name,
email,
message,
number_phone: phoneNumber,
role,
status
}
closeDialog('edit', data);
}
setId(0)
setName('')
}
}
const handleCancel = () => {
closeDialog('cancel', 'none')
setId(0)
setName('')
}
const onChangeStatus = (val) => {
setStatus(val)
}
const renderForm = () => {
return (
<Form>
<Row>
<Col md={12}>
<span style={{ color: "red" }}>*</span> Wajib diisi.
</Col>
</Row>
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('name')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder={t('inputName')}
/>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('email')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder={t('inputEmail')}
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('phoneNumber')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={phoneNumber}
onChange={(e) => setName(e.target.value)}
placeholder={t('inputNoPhone')}
/>
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">{t('role')}<span style={{ color: "red" }}>*</span></Label>
<Input
type="text"
value={role}
onChange={(e) => setRole(e.target.value)}
placeholder={t('inputRole')}
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col md={12}>
<FormGroup>
<Label className="capitalize">
{t('status')}<span style={{ color: "red" }}>*</span>
</Label>
<Select
showSearch
filterOption={(inputValue, option) =>
option.children.toLowerCase().includes(inputValue.toLowerCase())
}
value={status}
defaultValue={status}
onChange={onChangeStatus}
style={{ width: "100%" }}
>
<Option value="New Contact">New Contact</Option>
<Option value="Presentation">Presentation</Option>
<Option value="Live Demo">Live Demo</Option>
<Option value="Trial">Trial</Option>
<Option value="Go-Live">Go-Live</Option>
<Option value="Postpone">Postpone</Option>
</Select>
</FormGroup>
</Col>
</Row>
<Row>
<Col md={12}>
<FormGroup>
<Label className="capitalize">{t('message')}</Label>
<Input row="4" type="textarea" value={message} onChange={(e) => setMessage(e.target.value)} placeholder={t('inputMessage')} />
</FormGroup>
</Col>
</Row>
</Form>
)
}
return (
<>
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>{typeDialog == "Save" ? `Add` : "Edit"} {t('Demo')}</ModalHeader>
<ModalBody>
{renderForm()}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>{typeDialog}</Button>{' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>{t('cancel')}</Button>
</ModalFooter>
</Modal>
</>
)
}
export default DialogForm;

374
src/views/SimproV2/SalesContact/index.js

@ -0,0 +1,374 @@
import * as XLSX from 'xlsx';
import DialogForm from './DialogForm';
import React, { useState, useEffect } from 'react';
import SweetAlert from 'react-bootstrap-sweetalert';
import axios from "../../../const/interceptorApi"
import { Card, CardBody, CardHeader, Col, Row, Input, Table } from 'reactstrap';
import { SALES_CONTACT_EDIT, SALES_CONTACT_SEARCH, SALES_CONTACT_LIST, SALES_CONTACT_GET_ID, SALES_CONTACT_ADD, SALES_CONTACT_DELETE } from '../../../const/ApiConst';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Spin, Button, Tooltip } from 'antd';
import { useTranslation } from 'react-i18next';
const ProjectType = ({ params, ...props }) => {
let role_id = 0, user_id = 0, isLogin = false, token = '', company_id = 0, all_project = null, role_name = '', hierarchy = [], user_name = '';
if (props && props.role_id && props.user_id) {
role_id = props.role_id;
user_id = props.user_id;
token = props.token;
isLogin = props.isLogin;
company_id = props.company_id;
all_project = props.all_project;
role_name = props.role_name;
isLogin = props.isLogin;
hierarchy = props.hierarchy;
user_name = props.user_name;
}
const HEADER = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const pageName = params.name;
const [alertDelete, setAlertDelete] = useState(false)
const [allDataMenu, setAllDataMenu] = useState([])
const [clickOpenModal, setClickOpenModal] = useState(false)
const [currentPage, setCurrentPage] = useState(1)
const [dataEdit, setDataEdit] = useState([])
const [dataExport, setDataExport] = useState([])
const [dataTable, setDatatable] = useState([])
const [idDelete, setIdDelete] = useState(0)
const [openDialog, setOpenDialog] = useState(false)
const [rowsPerPage, setRowsPerPage] = useState(10)
const [search, setSearch] = useState("")
const [totalPage, setTotalPage] = useState(0)
const [typeDialog, setTypeDialog] = useState('Save')
const [dataDemo, setDataDemo] = useState([])
const [listCompany, setListCompany] = useState([])
const [loading, setLoading] = useState(true);
const { t } = useTranslation()
const column = [
{ name: t('name') },
{ name: t('company') },
{ name: t('email') },
{ name: t('roles') },
{ name: t('phoneNumber') },
{ name: t('status') },
{ name: t('description') },
].filter(column => column && column.name);
useEffect(() => {
getDataContactSales();
}, [currentPage, rowsPerPage, search])
useEffect(() => {
const cekData = dataExport || []
if (cekData.length > 0) {
exportExcel()
}
}, [dataExport])
const getDataContactSales = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = currentPage * rowsPerPage - rowsPerPage;
}
const payload = {
group_column: {
"operator": "AND",
"group_operator": "OR",
"where": [
{
"name": "name",
"logic_operator": "~*",
"value": search,
}
]
},
columns: [],
"orders": {
"ascending": true,
"columns": [
'id'
]
},
"paging": {
"length": rowsPerPage,
"start": start
},
'joins': []
}
const result = await axios
.post(SALES_CONTACT_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
setDatatable(result.data.data);
setTotalPage(result.data.totalRecord);
setLoading(false)
} else {
NotificationManager.error('Gagal Mengambil Data!!', 'Failed');
setLoading(false)
}
}
const handleExportExcel = async () => {
let start = 0;
if (currentPage !== 1 && currentPage > 1) {
start = (currentPage * rowsPerPage) - rowsPerPage
}
const payload = {
group_column: {
"operator": "AND",
"group_operator": "OR",
"where": [
{
"name": "name",
"logic_operator": "~*",
"value": search,
}
]
},
"columns": [],
"orders": {
"ascending": true,
"columns": [
'id'
]
},
"paging": {
"length": rowsPerPage,
"start": start
},
'joins': []
}
const result = await axios
.post(SALES_CONTACT_SEARCH, payload, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
let resData = result.data.data;
const excelData = [];
resData.map((val, index) => {
let dataRow = {};
dataRow["Nama"] = val.name;
dataRow["Email"] = val.email;
dataRow["Role"] = val.role;
dataRow["No Telepon"] = val.number_phone;
dataRow["Status"] = val.message;
dataRow["Message"] = val.message;
excelData.push(dataRow)
})
await setDataExport(excelData)
} else {
NotificationManager.error('Gagal Export Data!!', 'Failed');
}
}
const exportExcel = () => {
const dataExcel = dataExport || [];
const fileName = `Data ${pageName}.xlsx`;
const ws = XLSX.utils.json_to_sheet(dataExcel);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, `Data ${pageName}`);
XLSX.writeFile(wb, fileName);
setDataExport([])
}
const handleSearch = e => {
const value = e.target.value
setSearch(value);
setCurrentPage(1)
};
const handleOpenDialog = (type) => {
setOpenDialog(true)
setTypeDialog(type)
}
const handleEdit = (data) => {
setDataEdit(data)
handleOpenDialog('Edit');
}
const handleDelete = async (id) => {
await setAlertDelete(true)
await setIdDelete(id)
}
const handleCloseDialog = (type, data) => {
if (type === "save") {
saveContactSales(data);
} else if (type === "edit") {
editContactSales(data);
}
setDataEdit([])
setOpenDialog(false)
}
const saveContactSales = async (data) => {
const formData = data
const result = await axios.post(SALES_CONTACT_ADD, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataContactSales()
NotificationManager.success(`Data berhasil ditambahkan`, 'Success!!');
} else {
NotificationManager.error(`Data gagal ditambahkan`, 'Failed!!');
}
}
const editContactSales = async (data) => {
let urlEdit = SALES_CONTACT_EDIT(data.id)
const formData = data
const result = await axios.put(urlEdit, formData, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataContactSales();
NotificationManager.success(`Data berhasil diubah`, 'Success!!');
} else {
NotificationManager.error(`Data gagal diubah`, `Failed!!`);
}
}
const toggleAddDialog = () => {
setOpenDialog(!openDialog)
}
const onConfirmDelete = async () => {
let url = SALES_CONTACT_DELETE(idDelete);
const result = await axios.delete(url, HEADER)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataContactSales()
setIdDelete(0)
setAlertDelete(false)
NotificationManager.success(`Data berhasil dihapus!`, 'Success!!');
} else {
setIdDelete(0)
setAlertDelete(false)
NotificationManager.error(`Data gagal dihapus!}`, 'Failed!!');
}
}
const cancelDelete = () => {
setAlertDelete(false)
setIdDelete(0)
}
const onShowSizeChange = (current, pageSize) => {
setRowsPerPage(pageSize)
}
const onPagination = (current, pageSize) => {
setCurrentPage(current)
}
const dataNotAvailable = () => {
if (dataTable.length === 0) {
return (
<tr>
<td align="center" colSpan="8">{t('noData')}</td>
</tr>
)
}
}
return (
<div>
<NotificationContainer />
<SweetAlert
show={alertDelete}
warning
showCancel
confirmBtnText="Delete"
confirmBtnBsStyle="danger"
title={t('deleteConfirm')}
onConfirm={onConfirmDelete}
onCancel={cancelDelete}
focusCancelBtn
>
{t('deleteMsg')}
</SweetAlert>
<DialogForm
openDialog={openDialog}
closeDialog={handleCloseDialog}
toggleDialog={() => toggleAddDialog}
typeDialog={typeDialog}
dataEdit={dataEdit}
clickOpenModal={clickOpenModal}
dataParent={allDataMenu}
/>
<Card>
<CardHeader style={{ display: "flex", justifyContent: "space-between" }}>
<h4 className="capitalize">{pageName}</h4>
<Row>
<Col>
<Input onChange={handleSearch} value={search} type="text" name="search" id="search" placeholder={t('searchDemo')} />
</Col>
<Col>
<Tooltip title={t('demoAdd')}>
<Button style={{ background: "#4caf50", color: "#fff" }} onClick={() => handleOpenDialog('Save')}><i className="fa fa-plus"></i></Button>
</Tooltip>
<Tooltip title={t('exportExcel')}>
<Button style={{ marginLeft: "5px" }} onClick={() => handleExportExcel()}><i className="fa fa-print"></i></Button>
</Tooltip>
</Col>
</Row>
</CardHeader>
<CardBody>
<Spin tip="Loading..." spinning={loading}>
<Table responsive striped hover>
<thead>
<tr>
<th>Aksi</th>
{column.map((i, index) => {
return (
<th key={index} scope="row">{i.name}</th>
)
})}
</tr>
</thead>
<tbody>
{dataNotAvailable()}
{dataTable.map((n, index) => {
return (
<tr key={n.id}>
<td className='nowrap'>
<Tooltip title={t('delete')}>
<i id="TooltipDelete" className="fa fa-trash" style={{ color: 'red', marginRight: 10, cursor: "pointer" }} onClick={() => handleDelete(n.id)}></i>
</Tooltip>
<Tooltip title={t('edit')}>
<i id="TooltipEdit" className="fa fa-edit" style={{ color: 'green', cursor: "pointer" }} onClick={() => handleEdit(n)}></i>
</Tooltip>
</td>
<td>{n.name}</td>
<td>{n.company_name}</td>
<td>{n.email}</td>
<td>{n.role}</td>
<td>{n.number_phone}</td>
<td>{n.status}</td>
<td>{n.message}</td>
</tr>
)
})}
</tbody>
</Table>
</Spin>
</CardBody>
</Card>
</div>
)
}
export default ProjectType;

53
src/views/SimproV2/Settings/Desktop.js

@ -0,0 +1,53 @@
import Index from "./components/MyProfile/Index";
import styles from "./Desktop.module.css";
import Plan from "./components/Plan/Container1";
import React, { useState, useEffect } from 'react';
import { Nav, NavItem, NavLink, TabContent, TabPane } from 'reactstrap';
const Desktop = () => {
const [activeTab, setActiveTab] = useState('tab1')
const [typeTab, setTypeTab] = useState('myprofile')
return (
<main className={styles.myProfile}>
<section className={styles.profile}>
<Nav tabs>
<NavItem>
<NavLink
style={{ borderRadius: typeTab === 'myprofile' ? '15px' : '', backgroundColor: typeTab === 'myprofile' ? '#E0ECF5' : '', color: typeTab === 'myprofile' ? '#48A4F0' : '', fontWeight:'600', border:'none' }}
onClick={() => {
setActiveTab("tab1");
setTypeTab("myprofile");
}}
active={activeTab === "tab1"}
>
My Profile
</NavLink>
</NavItem>
<NavItem>
<NavLink
style={{ borderRadius: typeTab === 'plan' ? '15px' : '', backgroundColor: typeTab === 'plan' ? '#E0ECF5' : '', color: typeTab === 'plan' ? '#48A4F0' : '', fontWeight:'600', border:'none' }}
onClick={() => {
setActiveTab("tab2");
setTypeTab("plan");
}}
active={activeTab === "tab2"}
>
Plan
</NavLink>
</NavItem>
</Nav>
<TabContent activeTab={activeTab} style={{ border:'none' }}>
<TabPane tabId="tab1" style={{ border:'none' }}>
<Index/>
</TabPane>
<TabPane tabId="tab2" style={{ border:'none' }}>
<Plan/>
</TabPane>
</TabContent>
</section>
</main>
);
};
export default Desktop;

23
src/views/SimproV2/Settings/Desktop.module.css

@ -0,0 +1,23 @@
.myProfile,
.profile {
max-width: 100%;
}
.profile {
align-self: stretch;
padding: 15px 30px 30px;
box-sizing: border-box;
gap: 15px 0;
}
.myProfile {
width: 1300px;
border-radius: 30px;
background-color: #fff;
}
@media screen and (max-width: 1050px) {
.profile {
padding-top: 20px;
padding-bottom: 20px;
box-sizing: border-box;
}
}

176
src/views/SimproV2/Settings/DialogForm.js

@ -1,16 +1,15 @@
import React, { useEffect, useState } from 'react'
import {
Modal, ModalHeader, ModalBody, ModalFooter,
Button, Form, FormGroup, Label, Input, Col, Row,
Nav, NavItem, NavLink, TabContent, TabPane
Button, Form, FormGroup, Label, Input, Col, Row,TabContent, TabPane
} from 'reactstrap';
import { Select, DatePicker } from 'antd';
import moment from "moment";
import { BASE_SIMPRO_LUMEN_IMAGE_COMPANY } from '../../../const/ApiConst';
import profile from '../../../assets/img/profile.png'
const { Option } = Select
const DialogForm = ({
openDialog,
closeDialog,
@ -27,28 +26,34 @@ const DialogForm = ({
emailProp,
userNameProp,
refferalCode,
userProfile
userProfile,
imageProfile
}) => {
const token = window.localStorage.getItem('token');
const [typeDialog, setTypeDialog] = useState(typeDialogProp)
const [userName, setUserName] = useState(userNameProp)
const [name, setName] = useState(nameProp)
const [noHp, setNohp] = useState(noHpProp)
const [gender, setGender] = useState(genderProp)
const [address, setAddres] = useState(addressProp)
const [birthdayPlace, setBirthdayplace] = useState(birthdayPlaceProp)
const [birthdayDate, setBirthdaydate] = useState(birthdayDateProp)
const [birthdayDate, setBirthdaydate] = useState(birthdayDateProp && birthdayDateProp != null ? moment(birthdayDateProp) : moment())
const [idNumber, setIdnumber] = useState(idNumberProp)
const [email, setEmail] = useState(emailProp)
const [refferal, setRefferalCode] = useState('')
const [oldPassword, setOldPassword] = useState('')
const [newPassword, setNewPassword] = useState('')
const [newPasswordConfirm, setNewPasswordConfirm] = useState('')
const [activeTab, setActiveTab] = useState('tab1')
console.log('typeDialogProp',typeDialogProp)
const [profileImage, setImageProfile] = useState(null)
const [modalOpen, setModalOpen] = useState(false)
const role = window.localStorage.getItem('role_name');
let configApp = '';
if (role !== 'Super Admin') {
configApp = JSON.parse(window.localStorage.getItem('configApp'));
}
const handleSave = () => {
let data = '';
if (typeDialog === "Personal" && typeDialogProp !== "Refferal") {
if (typeDialogProp === "Personal" && typeDialogProp !== "Refferal") {
data = {
name: name,
phone_number: noHp,
@ -61,11 +66,14 @@ const DialogForm = ({
data.birth_date = birthdayDate;
}
closeDialog('profile', data)
} else if (typeDialog === "Account" && typeDialogProp !== "Refferal") {
} else if (typeDialogProp === "Account" || typeDialogProp === "Settings" && typeDialogProp !== "Refferal") {
data = {
username: userName,
email: email,
password: newPassword,
email: email
}
data.profilePicture = profileImage ? profileImage : null;
if(typeDialogProp === "Settings" && newPassword && oldPassword && newPasswordConfirm) {
data.password = newPassword;
}
closeDialog('profile', data)
} else {
@ -95,6 +103,10 @@ const DialogForm = ({
)
}
const handleDatePickerEnd = (date, dateString) => {
setBirthdaydate(date);
};
function generateRandomString(length) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
let result = '';
@ -109,30 +121,38 @@ const DialogForm = ({
setRefferalCode(newReferralCode);
}
const toggleModal = () => {
setModalOpen(!modalOpen);
};
const handleImageClick = async () => {
toggleModal();
};
const renderForm = () => {
return (
<Form>
<Row>
<Col md={6}>
<FormGroup>
<Label className="capitalize">Nama</Label>
<Label className="capitalize">Name</Label>
<Input type="text" value={name || nameProp} onChange={(e) => setName(e.target.value)} />
</FormGroup>
<FormGroup>
<Label className="capitalize">ID Number</Label>
<Label className="capitalize">Kode Number</Label>
<Input type="text" value={idNumber || idNumberProp} onChange={(e) => setIdnumber(e.target.value)} />
</FormGroup>
<FormGroup>
<Label className="capitalize">Alamat</Label>
<Label className="capitalize">Address</Label>
<Input type="text" value={address || addressProp} onChange={(e) => setAddres(e.target.value)} />
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">Nomor Handphone</Label>
<Label className="capitalize">Telephone</Label>
<Input type="text" value={noHp || noHpProp} onChange={(e) => setNohp(e.target.value)} />
</FormGroup>
@ -146,13 +166,13 @@ const DialogForm = ({
</FormGroup>
<FormGroup>
<Label className="capitalize">Tempat Lahir</Label>
<Label className="capitalize">Place of Birth</Label>
<Input type="text" value={birthdayPlace || birthdayPlaceProp} onChange={(e) => setBirthdayplace(e.target.value)} />
</FormGroup>
<FormGroup>
<Label className="capitalize">Tanggal Lahir</Label>
<DatePicker style={{ width: "100%" }} value={birthdayDate} defaultValue={birthdayDateProp} onChange={(date, dateString) => setBirthdaydate(date)} />
<Label className="capitalize">Date of Birth</Label>
<DatePicker style={{ width: "100%" }} value={birthdayDateProp && birthdayDateProp != null ? moment(birthdayDateProp) : birthdayDate} onChange={handleDatePickerEnd} />
</FormGroup>
</Col>
@ -165,31 +185,47 @@ const DialogForm = ({
return (
<Form>
<Row>
<Col md={6}>
<Col md={12}>
<FormGroup>
<Label className="capitalize" style={{ fontWeight: "bold" }}>Image Profile</Label>
<Input
type="file"
accept="image/*"
onChange={(e) => setImageProfile(e.target.files[0])}
/>
<small onClick={imageProfile ? () => handleImageClick() : ''} style={{ cursor: imageProfile ? "pointer" : "" }}>
<p style={{ textDecoration: imageProfile ? 'underline' : 'none', color: imageProfile ? 'blue' : 'red' }}>
{
imageProfile ? (
"View image"
) : (
"Not found image"
)
}
</p>
</small>
</FormGroup>
<FormGroup>
<Label className="capitalize">Username</Label>
<Input type="text" value={userName || userNameProp} onChange={(e) => setUserName(e.target.value)} />
</FormGroup>
<FormGroup>
<Label className="capitalize">Email</Label>
<Input type="text" value={email || emailProp} onChange={(e) => setEmail(e.target.value)} />
</FormGroup>
</Col>
<Col md={6}>
<Col md={12}>
<FormGroup>
<Label className="capitalize">Old password</Label>
<Label className="capitalize">Old Password</Label>
<Input type="text" value={oldPassword} onChange={(e) => setOldPassword(e.target.value)} />
</FormGroup>
<FormGroup>
<Label className="capitalize">New password</Label>
<Label className="capitalize">New Password</Label>
<Input type="text" value={newPassword} onChange={(e) => setNewPassword(e.target.value)} />
</FormGroup>
<FormGroup>
<Label className="capitalize">Confirm new password</Label>
<Label className="capitalize">Confirm New Password</Label>
<Input type="text" value={newPasswordConfirm} onChange={(e) => setNewPasswordConfirm(e.target.value)} />
</FormGroup>
</Col>
@ -207,10 +243,10 @@ const DialogForm = ({
<Label className="capitalize">Username</Label>
<Input type="text" value={userName || userNameProp} onChange={(e) => setUserName(e.target.value)} />
</FormGroup>
</Col>
<Col md={6}>
<FormGroup>
<Label className="capitalize">Email</Label>
<Input type="text" value={email || emailProp} onChange={(e) => setEmail(e.target.value)} />
</FormGroup>
</Col>
@ -220,56 +256,23 @@ const DialogForm = ({
}
return (
<>
{/* Form */}
<Modal size="lg" isOpen={openDialog} toggle={toggleDialog}>
<ModalHeader className="capitalize" toggle={closeDialog}>
Update {typeDialog == "Personal" ? `Personal` : "Account"} Data
Update {typeDialogProp} {typeDialogProp == 'Refferal' ? ' Code' : ' Data'}
</ModalHeader>
<ModalBody>
{typeDialogProp !== 'Refferal' ? (
<>
<Nav tabs>
<NavItem>
<NavLink
onClick={() => {
setActiveTab("tab1");
setTypeDialog("Personal");
}}
active={activeTab === "tab1"}
>
Personal
</NavLink>
</NavItem>
<NavItem>
<NavLink
onClick={() => {
setActiveTab("tab2");
setTypeDialog("Account");
}}
active={activeTab === "tab2"}
>
Account
</NavLink>
</NavItem>
<NavItem>
<NavLink
onClick={() => {
setActiveTab("tab3");
setTypeDialog("Setting");
}}
active={activeTab === "tab3"}
>
Setting
</NavLink>
</NavItem>
</Nav>
<TabContent activeTab={activeTab}>
<TabPane tabId="tab1">
<TabContent activeTab={typeDialogProp}>
<TabPane tabId="Personal">
{renderForm()}
</TabPane>
<TabPane tabId="tab2">
<TabPane tabId="Settings">
{renderFormAccount()}
</TabPane>
<TabPane tabId="tab3">
<TabPane tabId="Account">
{renderFormSetting()}
</TabPane>
</TabContent>
@ -278,7 +281,7 @@ const DialogForm = ({
<Form>
<Row>
<Col md={12}>
<span style={{ color: "red" }}>*</span> Wajib diisi.
<span style={{ color: "red" }}>*</span> Is required
</Col>
</Row>
<Row>
@ -300,14 +303,33 @@ const DialogForm = ({
)}
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={() => handleSave()}>{typeDialogProp !== 'Refferal' ? typeDialog == "Profile" ? `Profile` : "Save" : "Generate Code"}</Button> {' '}
<Button color="primary" onClick={() => handleSave()}>Save</Button> {' '}
<Button className="capitalize" color="secondary" onClick={() => handleCancel()}>Batal</Button>
</ModalFooter>
</Modal>
{/* Image Picture */}
<Modal isOpen={modalOpen} toggle={toggleModal}>
<ModalBody style={{ textAlign:'center' }}>
{
imageProfile ? (
<img
src={
imageProfile ? (
`${BASE_SIMPRO_LUMEN_IMAGE_COMPANY(imageProfile?.image, role != 'Super Admin' ? configApp.company_name : 'undifined')}`
) : profile
}
style={{ maxWidth: "100%" }}
alt="Image Preview"
/>
) : ('Image not found!')
}
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={toggleModal}>Close</Button>
</ModalFooter>
</Modal>
</>
)
}
export default DialogForm;

69
src/views/SimproV2/Settings/components/MyProfile/Head.module.css

@ -0,0 +1,69 @@
.obejct11 {
width: 55px;
height: 54px;
position: relative;
border-radius: 79.5px;
object-fit: cover;
}
.img {
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
padding: 20px 0;
}
.headContent {
position: relative;
font-weight: 600;
}
.headTitle {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: center;
}
.content {
position: relative;
font-weight: 600;
}
.headSubtitle {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: center;
font-size: 16px;
color: #777;
}
.head,
.text {
box-sizing: border-box;
display: flex;
}
.text {
width: 1032px;
flex-direction: column;
align-items: flex-start;
justify-content: center;
padding: 20px 0;
gap: 5px 0;
}
.head {
align-self: stretch;
height: 98px;
background-color: #fff;
border: 1px solid #7eacd3;
flex-shrink: 0;
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: 0 16px 0 14px;
gap: 0 20px;
text-align: left;
font-size: 20px;
color: #333;
}
@media screen and (max-width: 450px) {
.headContent {
font-size: 16px;
}
}

436
src/views/SimproV2/Settings/components/MyProfile/Index.js

@ -0,0 +1,436 @@
import * as XLSX from 'xlsx';
import React, { useState, useEffect, useMemo } from 'react';
import axios from "../../../../../const/interceptorApi"
import { NotificationContainer, NotificationManager } from 'react-notifications';
import { Pagination, Tooltip } from 'antd';
import { USER_EDIT, REFFERAL_ADD, REFFERAL_EDIT, ROLE_SEARCH, USER_SEARCH, IMAGE_UPLOAD, IMAGE_DELETE, IMAGE_GET_BY_ID, BASE_SIMPRO_LUMEN_IMAGE_COMPANY } from '../../../../../const/ApiConst';
import DialogForm from '../../DialogForm'
import styles from "./Index.module.css";
import profile from '../../../../../assets/img/profile.png'
import stylesHead from "./Head.module.css";
import moment from 'moment';
import { Modal, ModalBody, ModalFooter, Button } from 'reactstrap';
const Index = () => {
const token = localStorage.getItem("token")
const user_id = localStorage.getItem("user_id")
let company_id = '', configApp = '';
const role = window.localStorage.getItem('role_name');
if(role !== 'Super Admin') {
company_id = localStorage.getItem("company_id");
configApp = JSON.parse(window.localStorage.getItem('configApp'));
}
const config = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
const HEADER_MULTIPART = {
headers: {
"Content-Type": "multipart/form-data",
Authorization: `Bearer ${token}`,
},
};
const [openDialog, setOpenDialog] = useState(false)
const [typeDialog, setTypeDialog] = useState('')
const [roleList, setRoleList] = useState([])
const [refferal, setReferralCode] = useState(null)
const [isCopied, setIsCopied] = useState(false)
const [userProfile, setUserprofile] = useState(null)
const [imageProfile, setImageProfile] = useState(null);
const [modalOpen, setModalOpen] = useState(false)
useEffect(() => {
getImageProfle(parseInt(user_id));
getRoleList();
getDataProfileUser();
}, [])
const getDataProfileUser = async () => {
const formData = {
"paging": {"start": 0, "length": 1},
"columns": [
{"name": "id", "logic_operator": "=", "value": parseInt(user_id), "operator": "AND"}
],
"joins": [
{
"name": "m_divisi",
"column_join": "divisi_id",
"column_results": [
"name"
]
},
{
"name": "refferal_code",
"column_join": "discount_id",
"column_results": [
"code"
]
}
]
}
const result = await axios
.post(USER_SEARCH, formData, config)
.then(res => res)
.catch((error) => error.response );
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data[0];
setUserprofile(dataRes);
if(!dataRes.discount_id || dataRes.discount_id === null || dataRes.discount_id === '') {
saveRefferalCode(dataRes?.username, dataRes?.ktp_number);
} else {
setReferralCode(dataRes.join_second_code);
}
} else {
NotificationManager.error("Gagal Mengambil Data!!", "Failed");
}
}
const handleOpenDialog = (type) => {
setOpenDialog(true)
setTypeDialog(type)
}
const handleCloseDialog = (type, data) => {
if (type === "profile") {
saveProfile(data);
} else if(type === "refferal_code") {
updateRefferal(data);
}
setOpenDialog(false)
}
const saveProfile = async (data) => {
let urlEdit = USER_EDIT(user_id)
const formData = data
const result = await axios.put(urlEdit, formData, config)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
const profilePicture = data.profilePicture;
if (profilePicture && profilePicture != null) {
await deleteImageProfile(
parseInt(user_id),
);
await saveImageProfile(
parseInt(user_id),
profilePicture
);
}
getDataProfileUser()
getImageProfle(user_id)
NotificationManager.success(`Data profile berhasil diedit`, 'Success!!');
} else {
NotificationManager.error(`Data profile gagal di edit`, `Failed!!`);
}
}
// Save Image Function
const saveImageProfile = async (id, data) => {
const formData = new FormData;
formData.append('ref_id', id);
formData.append('category', 'profile_picture');
formData.append('files', data);
if(role !== 'Super Admin') {
formData.append('company_name', configApp.company_name);
}
await axios
.post(IMAGE_UPLOAD, formData, HEADER_MULTIPART)
.then(res => res)
.catch((error) => error.response);
};
// Delete Image Function
const deleteImageProfile = async (id) => {
const URL = IMAGE_DELETE(id, 'profile_picture', company_id != '' ? company_id : 'undifined');
await axios
.delete(URL, config)
.then(res => res)
.catch((error) => error.response);
};
const getImageProfle = async (id) => {
const url = IMAGE_GET_BY_ID(id, "profile_picture");
const result = await axios
.get(url, config)
.then((res) => res)
.catch((err) => err.response);
if (result && result.data && result.data.code === 200) {
setImageProfile(result.data.data);
}
}
const updateRefferal = async (data) => {
let urlEdit = REFFERAL_EDIT(userProfile?.id)
const formData = data
const result = await axios.put(urlEdit, formData, config)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code === 200) {
getDataProfileUser(data.user_id, data.username, data.ktp_number);
NotificationManager.success(`Code refferal berhasil diedit`, 'Success!!');
} else {
NotificationManager.error(`Code refferal gagal di edit`, `Failed!!`);
}
}
const toggleAddDialog = () => {
setOpenDialog(!openDialog)
}
const toggleModal = () => {
setModalOpen(!modalOpen);
};
const handleImageClick = async () => {
toggleModal();
};
const getRoleList = async () => {
const formData = {
"paging": { "start": 0, "length": -1 },
"orders": { "columns": ["id"], "ascending": false }
}
const result = await axios
.post(ROLE_SEARCH, formData, config)
.then(res => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
setRoleList(result.data.data);
}
}
const saveRefferalCode = async (username, ktp_number) => {
const formData = {
'code': username + ktp_number.substring(0, 4),
'amount': 0
}
const result = await axios
.post(REFFERAL_ADD, formData, config)
.then((res) => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
const data = {'discount_id': result.data.data.id};
await saveProfile(data);
} else {
NotificationManager.error('Kode refferal gagal ditambahkan!!', 'Failed');
}
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(() => {
setIsCopied(true);
setTimeout(() => setIsCopied(false), 2000);
}, (err) => {
console.error('Gagal menyalin teks ke clipboard: ', err);
});
}
return (
<>
<NotificationContainer />
<DialogForm
openDialog={openDialog}
closeDialog={handleCloseDialog}
toggleDialog={() => toggleAddDialog}
typeDialogProp={typeDialog}
roleList={roleList}
nameProp={userProfile?.name}
noHpProp={userProfile?.phone_number}
idNumberProp={userProfile?.ktp_number}
genderProp={userProfile?.gender}
divisiProp={userProfile?.join_first_name}
birthdayPlaceProp={userProfile?.birth_place}
birthdayDateProp={userProfile?.birth_date}
addressProp={userProfile?.address}
emailProp={userProfile?.email}
userNameProp={userProfile?.username}
refferalCode={refferal}
userProfile={userProfile}
imageProfile={imageProfile}
/>
<div className={stylesHead.head}>
<div className={stylesHead.img} style={{ cursor:imageProfile ? 'pointer' : '' }} onClick={imageProfile ? () => handleImageClick() : ''}>
<img className={stylesHead.obejct11} src={
imageProfile ? (
`${BASE_SIMPRO_LUMEN_IMAGE_COMPANY(imageProfile?.image, role != 'Super Admin' ? configApp.company_name : 'undifined')}`
) : profile
} />
</div>
<div className={stylesHead.text}>
<div className={stylesHead.headTitle}>
<div className={stylesHead.headContent}>
{userProfile && userProfile.name != null ? userProfile.name : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
<div className={stylesHead.headSubtitle}>
<div className={stylesHead.content}>
{userProfile && userProfile.username != null ? userProfile.username : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
</div>
<div className={styles.btnEdit1} style={{ color: '#969696' }} onClick={() => handleOpenDialog('Settings')}>
<div className={styles.icon}>
<i className="fa fa-edit" style={{ fontSize:'16px' }}></i>
</div>
<div className={styles.edit} style={{ fontSize:'16px' }}>Edit</div>
</div>
</div>
<footer className={styles.index1}>
<div className={styles.row}>
<div className={styles.column}>
<div className={styles.text}>
<div className={styles.headTitle}>
<div className={styles.codeReferal}>Refferal Code</div>
</div>
<div className={styles.headSubtitle}>
<div className={styles.ibnu212} style={{ color:'#20A8D8' }}>{refferal ? refferal : 'empty'}</div>
<Tooltip title= {!isCopied ? "Copy Refferal" : "Copied"}>
<span onClick={() => copyToClipboard(refferal ? refferal : 'empty')}>
{isCopied ?
<i className="fa fa-check" style={{ cursor:'pointer' }}></i>
:
<i className="fa fa-clipboard" style={{ cursor:'pointer' }}></i>}
</span>
</Tooltip>
</div>
</div>
<div className={styles.btnEdit1} onClick={() => handleOpenDialog('Refferal')}>
<div className={styles.icon}>
<i className="fa fa-edit"></i>
</div>
<div className={styles.edit}>Edit</div>
</div>
</div>
<div className={styles.row1}>
<div className={styles.column1}>
<div className={styles.accountInformation}>Account Information</div>
<div className={styles.btnEdit2} onClick={() => handleOpenDialog('Account')}>
<div className={styles.icon1}>
<i className="fa fa-edit"></i>
</div>
<div className={styles.edit1}>Edit</div>
</div>
</div>
<div className={styles.column2}>
<div className={styles.frameParent}>
<div className={styles.usernameParent}>
<div className={styles.username}>Username</div>
<div className={styles.ibnu}>
{userProfile && userProfile.username != null ? userProfile.username : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
<div className={styles.emailParent}>
<div className={styles.email}>Email</div>
<div className={styles.emailContent}>
{userProfile && userProfile.email != null ? userProfile.email : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
</div>
</div>
</div>
</div>
<div className={styles.row2}>
<div className={styles.row3}>
<div className={styles.personalInformation}>Personal Information</div>
<div className={styles.btnEdit3} onClick={() => handleOpenDialog('Personal')}>
<div className={styles.icon3}>
<i className="fa fa-edit"></i>
</div>
<div className={styles.edit2}>Edit</div>
</div>
</div>
<div className={styles.div}>
<div className={styles.row4}>
<div className={styles.column3}>
<div className={styles.name}>Name</div>
<div className={styles.content}>
{userProfile && userProfile.name != null ? userProfile.name : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
<div className={styles.column4}>
<div className={styles.noHp}>Telephone</div>
<div className={styles.birthDetailsColumn}>
{userProfile && userProfile.phone_number != null ? userProfile.phone_number : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
</div>
<div className={styles.row5}>
<div className={styles.column5}>
<div className={styles.idNumber}>Kode Number</div>
<div className={styles.div1}>
{userProfile && userProfile.ktp_number != null ? userProfile.ktp_number : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
<div className={styles.column6}>
<div className={styles.gender}>Gender</div>
<div className={styles.male}>
{userProfile && userProfile.gender != null ? userProfile.gender : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
</div>
<div className={styles.row6}>
<div className={styles.column7}>
<div className={styles.division}>Division</div>
<div className={styles.div2}>
{userProfile && userProfile.join_first_name != null ? userProfile.join_first_name : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
<div className={styles.column8}>
<div className={styles.placeOfBirth}>Place of Birth</div>
<div className={styles.div3}>
{userProfile && userProfile.birth_place != null ? userProfile.birth_place : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
</div>
<div className={styles.row7}>
<div className={styles.column9}>
<div className={styles.role}>Role</div>
<div className={styles.div4}>
{userProfile && userProfile.employee_type != null ? userProfile.employee_type : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
<div className={styles.column10}>
<div className={styles.dateOfBirth}>Date of Birth</div>
<div className={styles.div5}>
{userProfile && userProfile.birth_date != null ? userProfile.birth_date : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
</div>
<div className={styles.row8}>
<div className={styles.column11}>
<div className={styles.address}>Address</div>
<div className={styles.div6}>
{userProfile && userProfile.address != null ? userProfile.address : <small style={{ fontStyle: 'italic', color:'gray' }}>empty</small>}
</div>
</div>
</div>
</div>
</div>
</footer>
<Modal isOpen={modalOpen} toggle={toggleModal}>
<ModalBody style={{ textAlign:'center' }}>
{
imageProfile ? (
<img
src={
imageProfile ? (
`${BASE_SIMPRO_LUMEN_IMAGE_COMPANY(imageProfile?.image, role != 'Super Admin' ? configApp.company_name : 'undifined')}`
) : profile
}
style={{ maxWidth: "100%" }}
alt="Image Preview"
/>
) : ('Image not found!')
}
</ModalBody>
<ModalFooter>
<Button color="secondary" onClick={toggleModal}>Close</Button>
</ModalFooter>
</Modal>
</>
);
};
export default Index;

563
src/views/SimproV2/Settings/components/MyProfile/Index.module.css

@ -0,0 +1,563 @@
.codeReferal {
position: relative;
font-weight: 600;
}
.headTitle {
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: center;
}
.copyIcon,
.ibnu212 {
position: relative;
}
.copyIcon {
height: 16px;
width: 16px;
overflow: hidden;
flex-shrink: 0;
}
.headSubtitle,
.text {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
gap: 0 10px;
color: #777;
}
.text {
flex: 1;
flex-direction: column;
align-items: flex-start;
justify-content: center;
gap: 5px 0;
min-width: 640px;
max-width: 100%;
color: #333;
}
.copyIcon1 {
height: 24px;
width: 24px;
position: relative;
overflow: hidden;
flex-shrink: 0;
}
.copy {
position: relative;
font-weight: 600;
}
.btnEdit {
border-radius: 20px;
border: 1px solid #969696;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: 5px 11px 5px 9px;
gap: 0 11px;
}
.editTextIcon {
height: 20px;
width: 18px;
position: relative;
}
.icon {
overflow: hidden;
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
padding: 5px 8px;
box-sizing: border-box;
width: 24px;
height: 24px;
}
.edit {
position: relative;
font-weight: 600;
}
.btnEdit1,
.column {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
.btnEdit1 {
border-radius: 20px;
border: 1px solid #969696;
padding: 5px 11px 5px 9px;
gap: 0 11px;
cursor: pointer;
}
.column {
align-self: stretch;
background-color: #fff;
border: 1px solid #7eacd3;
box-sizing: border-box;
flex-wrap: wrap;
padding: 20px 21px 20px 19px;
gap: 0 20px;
max-width: 100%;
}
.accountInformation {
position: relative;
font-weight: 600;
}
.icon2 {
height: 20px;
width: 18px;
position: relative;
}
.icon1 {
overflow: hidden;
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
padding: 5px 8px;
box-sizing: border-box;
width: 24px;
height: 24px;
}
.edit1 {
position: relative;
font-weight: 600;
}
.btnEdit2,
.column1 {
display: flex;
flex-direction: row;
}
.btnEdit2 {
border-radius: 20px;
border: 1px solid #969696;
align-items: center;
justify-content: flex-start;
padding: 5px 11px 5px 9px;
gap: 0 11px;
color: #969696;
cursor: pointer;
}
.column1 {
align-self: stretch;
align-items: flex-start;
justify-content: space-between;
gap: 20px;
}
.ibnu,
.username {
position: relative;
}
.username {
font-weight: 500;
}
.ibnu {
color: #777;
}
.usernameParent {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 10px 0;
min-width: 378px;
max-width: 100%;
}
.email {
position: relative;
font-weight: 500;
}
.emailContent {
position: relative;
color: #777;
white-space: nowrap;
}
.emailParent,
.frameParent {
display: flex;
align-items: flex-start;
justify-content: flex-start;
max-width: 100%;
}
.emailParent {
flex: 1;
flex-direction: column;
gap: 10px 0;
min-width: 378px;
}
.frameParent {
align-self: stretch;
flex-direction: row;
flex-wrap: wrap;
padding: 0 1px 0 0;
box-sizing: border-box;
gap: 0 37px;
}
.column2,
.row,
.row1 {
align-self: stretch;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
max-width: 100%;
}
.row1 {
background-color: #fff;
border: 1px solid #7eacd3;
box-sizing: border-box;
padding: 20px 21px 20px 19px;
gap: 10px 0;
color: #333;
}
.row {
gap: 15px 0;
}
.personalInformation {
position: relative;
font-weight: 500;
}
.vectorIcon {
height: 20px;
width: 18px;
position: relative;
}
.icon3 {
overflow: hidden;
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
padding: 5px 8px;
box-sizing: border-box;
width: 24px;
height: 24px;
}
.edit2 {
position: relative;
font-weight: 600;
}
.btnEdit3,
.row3 {
display: flex;
flex-direction: row;
}
.btnEdit3 {
border-radius: 20px;
border: 1px solid #969696;
align-items: center;
justify-content: flex-start;
padding: 5px 11px 5px 9px;
gap: 0 11px;
color: #969696;
cursor: pointer;
}
.row3 {
align-self: stretch;
align-items: flex-start;
justify-content: space-between;
gap: 20px;
}
.name {
position: relative;
font-weight: 500;
}
.content {
position: relative;
color: #777;
}
.column3 {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 10px 0;
min-width: 378px;
max-width: 100%;
}
.noHp {
position: relative;
font-weight: 500;
}
.birthDetailsColumn {
position: relative;
color: #777;
}
.column4,
.row4 {
display: flex;
align-items: flex-start;
justify-content: flex-start;
max-width: 100%;
}
.column4 {
flex: 1;
flex-direction: column;
gap: 10px 0;
min-width: 378px;
}
.row4 {
align-self: stretch;
flex-direction: row;
flex-wrap: wrap;
padding: 0 1px 0 0;
box-sizing: border-box;
gap: 0 37px;
}
.div1,
.idNumber {
position: relative;
}
.idNumber {
font-weight: 500;
}
.div1 {
color: #777;
}
.column5 {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 10px 0;
min-width: 378px;
max-width: 100%;
}
.gender,
.male {
position: relative;
}
.gender {
font-weight: 500;
}
.male {
color: #777;
}
.column6,
.row5 {
display: flex;
align-items: flex-start;
justify-content: flex-start;
max-width: 100%;
}
.column6 {
flex: 1;
flex-direction: column;
gap: 10px 0;
min-width: 378px;
}
.row5 {
align-self: stretch;
flex-direction: row;
flex-wrap: wrap;
padding: 0 1px 0 0;
box-sizing: border-box;
gap: 0 37px;
}
.div2,
.division {
position: relative;
}
.division {
font-weight: 500;
}
.div2 {
color: #777;
}
.column7 {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 10px 0;
min-width: 378px;
max-width: 100%;
}
.placeOfBirth {
position: relative;
font-weight: 500;
}
.div3 {
position: relative;
color: #777;
}
.column8,
.row6 {
display: flex;
align-items: flex-start;
justify-content: flex-start;
max-width: 100%;
}
.column8 {
flex: 1;
flex-direction: column;
gap: 10px 0;
min-width: 378px;
}
.row6 {
align-self: stretch;
flex-direction: row;
flex-wrap: wrap;
padding: 0 1px 0 0;
box-sizing: border-box;
gap: 0 37px;
}
.div4,
.role {
position: relative;
}
.role {
font-weight: 500;
}
.div4 {
color: #777;
}
.column9 {
flex: 1;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 10px 0;
min-width: 378px;
max-width: 100%;
}
.dateOfBirth {
position: relative;
font-weight: 500;
}
.div5 {
position: relative;
color: #777;
}
.column10,
.row7 {
display: flex;
align-items: flex-start;
justify-content: flex-start;
max-width: 100%;
}
.column10 {
flex: 1;
flex-direction: column;
gap: 10px 0;
min-width: 378px;
}
.row7 {
align-self: stretch;
flex-direction: row;
flex-wrap: wrap;
padding: 0 1px 0 0;
box-sizing: border-box;
gap: 0 37px;
}
.address {
font-weight: 500;
}
.address,
.div6 {
position: relative;
}
.div6 {
color: #777;
}
.column11,
.row8 {
display: flex;
align-items: flex-start;
justify-content: flex-start;
max-width: 100%;
}
.column11 {
flex: 1;
flex-direction: column;
gap: 10px 0;
}
.row8 {
align-self: stretch;
flex-direction: row;
}
.div {
gap: 20px 0;
}
.div,
.index1,
.row2 {
align-self: stretch;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
max-width: 100%;
}
.row2 {
background-color: #fff;
border: 1px solid #7eacd3;
box-sizing: border-box;
padding: 20px 21px 20px 19px;
gap: 10px 0;
color: #333;
}
.index1 {
gap: 15px 0;
text-align: left;
font-size: 16px;
color: #969696;
}
@media screen and (max-width: 1050px) {
.text {
min-width: 100%;
}
}
@media screen and (max-width: 750px) {
.emailParent,
.usernameParent {
min-width: 100%;
}
.frameParent {
gap: 0 37px;
}
.column3,
.column4 {
min-width: 100%;
}
.row4 {
gap: 0 37px;
}
.column5,
.column6 {
min-width: 100%;
}
.row5 {
gap: 0 37px;
}
.column7,
.column8 {
min-width: 100%;
}
.row6 {
gap: 0 37px;
}
.column10,
.column9 {
min-width: 100%;
}
.row7,
.row8 {
gap: 0 37px;
}
}
@media screen and (max-width: 450px) {
.column1,
.row3 {
flex-wrap: wrap;
}
}

65
src/views/SimproV2/Settings/components/Plan/Column.js

@ -0,0 +1,65 @@
import { useMemo } from "react";
import styles from "./Column.module.css";
const Column = ({
date,
currentPlanFrame,
textFrame,
currentPlanText,
text,
daysFrame,
propHeight,
propMinHeight,
propFlex,
propHeight1,
propFlex1,
propWidth,
}) => {
const columnStyle = useMemo(() => {
return {
height: propHeight,
};
}, [propHeight]);
const headStyle = useMemo(() => {
return {
minHeight: propMinHeight,
flex: propFlex,
};
}, [propMinHeight, propFlex]);
const dateStyle = useMemo(() => {
return {
height: propHeight1,
flex: propFlex1,
width: propWidth,
};
}, [propHeight1, propFlex1, propWidth]);
return (
<div className={styles.column} style={columnStyle}>
<div className={styles.head} style={headStyle}>
<div className={styles.date} style={dateStyle}>
{date}
</div>
</div>
<div className={styles.head1}>
<div className={styles.currentPlanFrame}>{currentPlanFrame}</div>
</div>
<div className={styles.head2}>
<div className={styles.textFrame}>{textFrame}</div>
</div>
<div className={styles.head3}>
<div className={styles.currentPlanText}>{currentPlanText}</div>
</div>
<div className={styles.head4}>
<div className={styles.text}>{text}</div>
</div>
<div className={styles.head5}>
<div className={styles.daysFrame}>{daysFrame}</div>
</div>
</div>
);
};
export default Column;

114
src/views/SimproV2/Settings/components/Plan/Column.module.css

@ -0,0 +1,114 @@
.date,
.head {
max-width: 100%;
}
.date {
height: 19px;
flex: 1;
position: relative;
line-height: 22px;
font-weight: 600;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
}
.head {
align-self: stretch;
border-bottom: 1px solid #d8d8d8;
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 8px;
min-height: 59px;
color: #969696;
}
.currentPlanFrame {
position: relative;
line-height: 22px;
}
.head1 {
align-self: stretch;
background-color: #fdfdfd;
border-bottom: 1px solid #d8d8d8;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 16px 8px;
white-space: nowrap;
}
.textFrame {
position: relative;
line-height: 22px;
}
.head2 {
align-self: stretch;
background-color: #fdfdfd;
border-bottom: 1px solid #d8d8d8;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 16px 8px;
white-space: nowrap;
}
.currentPlanText {
position: relative;
line-height: 22px;
}
.head3 {
align-self: stretch;
background-color: #fdfdfd;
border-bottom: 1px solid #d8d8d8;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 16px 8px;
white-space: nowrap;
}
.text {
position: relative;
line-height: 22px;
}
.head4 {
align-self: stretch;
background-color: #fdfdfd;
border-bottom: 1px solid #d8d8d8;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 16px 8px;
white-space: nowrap;
}
.daysFrame {
position: relative;
line-height: 22px;
}
.column,
.head5 {
display: flex;
align-items: center;
}
.head5 {
align-self: stretch;
background-color: #fdfdfd;
border-bottom: 1px solid #d8d8d8;
flex-direction: row;
justify-content: center;
padding: 16px 8px;
white-space: nowrap;
}
.column {
width: 400px;
flex-shrink: 0;
flex-direction: column;
justify-content: flex-start;
text-align: center;
font-size: 18px;
color: #333;
font-family: Roboto;
}

69
src/views/SimproV2/Settings/components/Plan/Container.js

@ -0,0 +1,69 @@
import Column from "./Column";
import styles from "./Container.module.css";
import React, { useState, useEffect } from 'react';
const Container = () => {
return (
<section className={styles.container}>
<div className={styles.headText}>
<div className={styles.paymentHistory}>Payment history</div>
</div>
<div className={styles.table}>
<Column
date="Date"
currentPlanFrame="9-02-2024 07:47:29"
textFrame="9-01-2024 07:47:29"
currentPlanText="9-12-2023 07:47:29"
text="9-11-2023 07:47:29"
daysFrame="9-10-2023 07:47:29"
/>
<Column
date="Amount"
currentPlanFrame="250k"
textFrame="250k"
currentPlanText="250k"
text="250k"
daysFrame="250k"
propHeight="333.4px"
propMinHeight="unset"
propFlex="1"
propHeight1="unset"
propFlex1="unset"
propWidth="64px"
/>
<div className={styles.column}>
<div className={styles.head}>
<div className={styles.status}>Status</div>
</div>
<div className={styles.head1}>
<div className={styles.successfulWrapper}>
<div className={styles.successful}>Successful</div>
</div>
</div>
<div className={styles.head2}>
<div className={styles.successfulContainer}>
<div className={styles.successful1}>Successful</div>
</div>
</div>
<div className={styles.head3}>
<div className={styles.successfulFrame}>
<div className={styles.successful2}>Successful</div>
</div>
</div>
<div className={styles.head4}>
<div className={styles.frameDiv}>
<div className={styles.successful3}>Successful</div>
</div>
</div>
<div className={styles.head5}>
<div className={styles.successfulWrapper1}>
<div className={styles.successful4}>Successful</div>
</div>
</div>
</div>
</div>
</section>
);
};
export default Container;

229
src/views/SimproV2/Settings/components/Plan/Container.module.css

@ -0,0 +1,229 @@
.paymentHistory {
position: relative;
font-weight: 500;
}
.headText {
align-self: stretch;
height: 34px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
.status {
width: 53px;
position: relative;
line-height: 22px;
font-weight: 600;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.head {
align-self: stretch;
flex: 1;
border-bottom: 1px solid #d8d8d8;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
padding: 8px;
color: #969696;
}
.successful {
flex: 1;
position: relative;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.head1,
.successfulWrapper {
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
}
.successfulWrapper {
width: 109px;
border-radius: 20px;
background-color: #17c13e;
justify-content: flex-start;
padding: 3px 10px;
}
.head1 {
align-self: stretch;
height: 54.8px;
background-color: #fdfdfd;
border-bottom: 1px solid #d8d8d8;
justify-content: center;
padding: 16px 8px;
}
.successful1 {
flex: 1;
position: relative;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.head2,
.successfulContainer {
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
}
.successfulContainer {
width: 109px;
border-radius: 20px;
background-color: #17c13e;
justify-content: flex-start;
padding: 3px 10px;
}
.head2 {
align-self: stretch;
height: 54.8px;
background-color: #fdfdfd;
border-bottom: 1px solid #d8d8d8;
justify-content: center;
padding: 16px 8px;
}
.successful2 {
flex: 1;
position: relative;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.head3,
.successfulFrame {
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
}
.successfulFrame {
width: 109px;
border-radius: 20px;
background-color: #17c13e;
justify-content: flex-start;
padding: 3px 10px;
}
.head3 {
align-self: stretch;
height: 54.8px;
background-color: #fdfdfd;
border-bottom: 1px solid #d8d8d8;
justify-content: center;
padding: 16px 8px;
}
.successful3 {
flex: 1;
position: relative;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.frameDiv,
.head4 {
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
}
.frameDiv {
width: 109px;
border-radius: 20px;
background-color: #17c13e;
justify-content: flex-start;
padding: 3px 10px;
}
.head4 {
align-self: stretch;
height: 54.8px;
background-color: #fdfdfd;
border-bottom: 1px solid #d8d8d8;
justify-content: center;
padding: 16px 8px;
}
.successful4 {
flex: 1;
position: relative;
line-height: 22px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.head5,
.successfulWrapper1 {
box-sizing: border-box;
display: flex;
flex-direction: row;
align-items: center;
}
.successfulWrapper1 {
width: 109px;
border-radius: 20px;
background-color: #17c13e;
justify-content: flex-start;
padding: 3px 10px;
}
.head5 {
align-self: stretch;
height: 54.8px;
background-color: #fdfdfd;
border-bottom: 1px solid #d8d8d8;
justify-content: center;
padding: 16px 8px;
}
.column,
.container,
.table {
display: flex;
justify-content: flex-start;
}
.column {
height: 333.4px;
width: 400px;
flex-shrink: 0;
flex-direction: column;
align-items: center;
color: #fdfdfd;
}
.container,
.table {
align-items: flex-start;
max-width: 100%;
}
.table {
width: 1200px;
border-radius: 4px;
background-color: #fdfdfd;
overflow-x: auto;
flex-direction: row;
text-align: center;
font-size: 18px;
}
.container {
width: 1240px;
background-color: #fff;
border: 1px solid #7eacd3;
box-sizing: border-box;
flex-direction: column;
padding: 20px 21px 20px 19px;
gap: 10px 0;
text-align: left;
font-size: 20px;
color: #333;
font-family: Roboto;
}
@media screen and (max-width: 450px) {
.paymentHistory {
font-size: 16px;
}
}

226
src/views/SimproV2/Settings/components/Plan/Container1.js

@ -0,0 +1,226 @@
import styles from "./Container1.module.css";
import React, { useState, useEffect } from 'react';
import axios from "../../../../../const/interceptorApi"
import { PROYEK_SEARCH, TRANSACTION_SEARCH, STORAGE_LIMIT_INFORMATION } from '../../../../../const/ApiConst';
import { NotificationContainer, NotificationManager } from 'react-notifications';
import moment from "moment";
const Container1 = () => {
const token = localStorage.getItem("token")
const user_id = localStorage.getItem("user_id")
let company_id = '', configApp = '';
const role = window.localStorage.getItem('role_name');
const [totalPage, setTotalPage] = useState(0);
const [transaction, setTransaction] = useState([]);
const [storage, setLimitInformation] = useState(0)
const currentDate = new Date();
const givenDate = new Date(transaction.exp_ospro);
const createdDate = new Date(transaction.created_at)
const differenceInMillis = givenDate.getTime() - currentDate.getTime();
const differenceInDays = Math.floor(differenceInMillis / (1000 * 60 * 60 * 24));
if(role !== 'Super Admin') {
company_id = localStorage.getItem("company_id");
configApp = JSON.parse(window.localStorage.getItem('configApp'));
}
const config = {
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
useEffect(()=>{
getDataProyek();
getDataTransaction();
getLimitInformation();
},[])
const getDataProyek = async () => {
const payload = {
"columns": [
{"name": "company_id", "logic_operator": "=", "value": parseInt(company_id), "operator": "AND"}
],
"select": [
"nama",
"mulai_proyek",
"akhir_proyek",
"company_id"
],
};
const result = await axios
.post(PROYEK_SEARCH, payload, config)
.then((res) => res)
.catch((error) => error.response);
if (result && result.data && result.data.code == 200) {
setTotalPage(result.data.totalRecord);
} else {
NotificationManager.error("Gagal Mengambil Data!!", "Failed");
}
};
const getDataTransaction = async () => {
const formData = {
"paging": {"start": 0, "length": 1},
"columns": [
{"name": "company_id", "logic_operator": "=", "value": parseInt(company_id), "operator": "AND"}
],
"select": [
"company_id",
"type_paket",
"amount",
"exp_ospro",
"pay_date",
"created_at"
]
}
const result = await axios
.post(TRANSACTION_SEARCH, formData, config)
.then(res => res)
.catch((error) => error.response );
if (result && result.data && result.data.code == 200) {
let dataRes = result.data.data[0];
setTransaction(dataRes);
} else {
NotificationManager.error("Gagal Mengambil Data!!", "Failed");
}
}
const getLimitInformation = async () => {
const url = STORAGE_LIMIT_INFORMATION(configApp.company_name);
const result = await axios
.get(url, config)
.then((res) => res)
.catch((error) => error.response);
if (result.data) {
setLimitInformation(result.data);
} else {
NotificationManager.error("Gagal Mengambil Data!!", "Failed");
}
}
return (
<section className={styles.container}>
<div className={styles.projectFrame}>
<div className={styles.currentPlan}>Current Plan</div>
<div className={styles.div}>
<div className={styles.div1}>
<div className={styles.text}>
<div className={styles.payNowCancelFrame}>
<div className={styles.yourCurrentPlan}>
Your Current Plan is <span style={{ color: "#59b4c3", fontWeight: '600' }}>{transaction.type_paket}</span>
</div>
<div className={styles.aSimpleStart}>
A simple start for everyone
</div>
</div>
</div>
<div className={styles.notificationText}>
<div className={styles.activeUntilMarc092024Parent}>
<div className={styles.activeUntilMarc}>
Active until <span style={{ color: "#59b4c3", fontWeight: '600' }}>{moment(transaction.exp_ospro).format('DD MMMM, YYYY')}</span>
</div>
<div className={styles.weWillSend}>
We will send you a notification upon Subscription expiration
</div>
</div>
</div>
<div className={styles.notificationText1}>
<div className={styles.paymentOf250kParent}>
<div className={styles.paymentOf250k}>Payment of 250k</div>
<div className={styles.paymentIsDue}>
Payment is due 9 March, 2024
</div>
</div>
</div>
</div>
<div className={styles.containerFrame}>
<button className={styles.payNowCancelSubscribe}>
<div className={styles.payNow}>Pay Now</div>
</button>
<button className={styles.payNowCancelSubscribe1}>
<div className={styles.cancelSubscription}>
Cancel Subscription
</div>
</button>
</div>
</div>
</div>
<div className={styles.daysOfDaysFrame}>
<div className={styles.days}>
<div className={styles.frameYourCurrentPlan}>
<div className={styles.days1}>Days</div>
<div className={styles.of30Days}>{30 - Math.abs(differenceInDays)} of 30 Days</div>
</div>
<div className={styles.rectangleFrame}>
<div className={styles.rectangleFrameChild} />
<div style={{
width: `${(400 * (30 - Math.abs(differenceInDays))) / 30}px`,
position: 'relative',
backgroundColor: ((30 - Math.abs(differenceInDays)) >= 0 && (30 - Math.abs(differenceInDays)) <= 10) ? '#59b4c3' :
((30 - Math.abs(differenceInDays)) >= 11 && (30 - Math.abs(differenceInDays)) <= 20) ? '#ffa447' :
'#FF4747',
zIndex:'1',
padding:'5px',
borderRadius:'15px'
}}>
</div>
</div>
<div className={styles.daysRemainingUntil}>
{Math.abs(differenceInDays)} days remaining until your plan requires update
</div>
</div>
<div className={styles.days2}>
<div className={styles.storageParent}>
<div className={styles.storage}>Storage</div>
<div className={styles.of500mb}>{storage} of {transaction.type_paket === 'Basic' ? 500 : 50}MB</div>
</div>
<div className={styles.rectangleParent}>
<div className={styles.frameChild} />
<div style={{
width: `${(400 * storage) / (transaction.type_paket === 'Basic' ? 500 : 50)}px`,
position: 'relative',
backgroundColor: (storage >= 0 && storage <= (transaction.type_paket === 'Basic' ? 166.67 : 16.67)) ? '#59b4c3' :
(storage >= (transaction.type_paket === 'Basic' ? 166.68 : 16.68) && storage <= (transaction.type_paket === 'Basic' ? 333.33 : 33.33)) ? '#ffa447' :
'#FF4747',
zIndex:'1',
padding:'5px',
borderRadius:'15px'
}}>
</div>
</div>
<div className={styles.storageRemainingUntil}>
{((storage / (transaction.type_paket === 'Basic' ? 500 : 50)) * 100).toFixed(2)}% storage remaining until your plan requires update
</div>
</div>
<div className={styles.days3}>
<div className={styles.projectParent}>
<div className={styles.project}>Project</div>
<div className={styles.of10Project}>{parseInt(totalPage)} of {transaction.type_paket === "Basic" ? "10" : "1"} Project</div>
</div>
<div className={styles.rectangleGroup}>
<div className={styles.frameInner} />
<div style={{
width: `${(400 * parseInt(totalPage)) / (parseInt(transaction.type_paket === "Basic" ? 10 : 1))}px`,
position: 'relative',
backgroundColor: transaction.type_paket === "Basic" ? (parseInt(totalPage) >= 0 && parseInt(totalPage) <= 3) ? '#59b4c3' :
(parseInt(totalPage) >= 4 && parseInt(totalPage) <= 7) ? '#ffa447' :
'#FF4747' : '#FF4747',
zIndex:'1',
padding:'5px',
borderRadius:'15px'
}}>
</div>
</div>
<div className={styles.projectRemainingUntil}>
{parseInt(transaction.type_paket === "Basic" ? 10 : 1) - (parseInt(totalPage))} Project remaining until your plan requires update
</div>
</div>
</div>
</section>
);
};
export default Container1;

356
src/views/SimproV2/Settings/components/Plan/Container1.module.css

@ -0,0 +1,356 @@
.currentPlan,
.yourCurrentPlan {
position: relative;
font-weight: 500;
}
.aSimpleStart {
position: relative;
color: #777;
}
.payNowCancelFrame,
.text {
display: flex;
align-items: flex-start;
max-width: 100%;
}
.payNowCancelFrame {
flex: 1;
flex-direction: column;
justify-content: flex-start;
gap: 10px 0;
}
.text {
align-self: stretch;
flex-direction: row;
justify-content: center;
}
.activeUntilMarc {
position: relative;
font-weight: 500;
}
.weWillSend {
align-self: stretch;
position: relative;
color: #777;
}
.activeUntilMarc092024Parent,
.notificationText {
display: flex;
align-items: flex-start;
max-width: 100%;
}
.activeUntilMarc092024Parent {
flex: 1;
flex-direction: column;
justify-content: flex-start;
gap: 10px 0;
}
.notificationText {
align-self: stretch;
flex-direction: row;
justify-content: center;
}
.paymentIsDue,
.paymentOf250k {
position: relative;
font-weight: 500;
}
.paymentIsDue {
color: #777;
}
.div1,
.notificationText1,
.paymentOf250kParent {
display: flex;
align-items: flex-start;
max-width: 100%;
}
.paymentOf250kParent {
flex: 1;
flex-direction: column;
justify-content: flex-start;
gap: 10px 0;
}
.div1,
.notificationText1 {
align-self: stretch;
flex-direction: row;
justify-content: center;
}
.div1 {
flex-direction: column;
justify-content: flex-start;
gap: 20px 0;
}
.payNow {
position: relative;
font-size: 18px;
font-weight: 500;
color: #fdfdfd;
text-align: left;
}
.payNowCancelSubscribe {
cursor: pointer;
border: 0;
padding: 10px 15px;
background-color: #20a8d8;
border-radius: 15px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
white-space: nowrap;
}
.payNowCancelSubscribe:hover {
background-color: #058fbf;
}
.cancelSubscription {
position: relative;
font-size: 18px;
font-weight: 500;
color: #ea5455;
text-align: left;
}
.payNowCancelSubscribe1 {
cursor: pointer;
border: 0;
padding: 10px 15px;
background-color: #fce4e4;
border-radius: 15px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
white-space: nowrap;
}
.payNowCancelSubscribe1:hover {
background-color: #e3c9c9;
}
.containerFrame,
.div,
.projectFrame {
display: flex;
justify-content: flex-start;
}
.containerFrame {
flex-direction: row;
align-items: center;
gap: 0 20px;
}
.div,
.projectFrame {
flex-direction: column;
align-items: flex-start;
max-width: 100%;
}
.div {
align-self: stretch;
gap: 20px 0;
font-size: 16px;
}
.projectFrame {
flex: 1;
gap: 15px 0;
min-width: 390px;
flex-shrink: 0;
}
.days1,
.of30Days {
position: relative;
}
.frameYourCurrentPlan {
width: 400px;
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
gap: 20px;
}
.rectangleFrameChild {
width: 600px;
position: relative;
background-color: #d9d9d9;
display: none;
}
.daysRemaining,
.rectangleFrame,
.rectangleFrameChild {
width: 400px;
border-radius: 5px;
max-width: 100%;
}
.rectangleFrame {
height: 10px;
background-color: #d9d9d9;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: 0 1px;
box-sizing: border-box;
}
.daysRemainingUntil {
position: relative;
display: inline-block;
max-width: 100%;
}
.days {
width: 600px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 5px 0;
}
.of500mb,
.storage {
position: relative;
}
.storageParent {
width: 400px;
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
gap: 20px;
}
.frameChild {
width: 600px;
position: relative;
background-color: #d9d9d9;
display: none;
}
.frameChild,
.frameItem,
.rectangleParent {
width: 400px;
border-radius: 5px;
max-width: 100%;
}
.frameItem {
width: 539.1px;
position: relative;
background-color: #ffa447;
z-index: 1;
}
.rectangleParent {
height: 10px;
background-color: #d9d9d9;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
padding: 0 1px;
box-sizing: border-box;
}
.storageRemainingUntil {
align-self: stretch;
position: relative;
}
.days2 {
width: 600px;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 5px 0;
}
.of10Project,
.project {
position: relative;
}
.projectParent {
width: 400px;
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: space-between;
gap: 20px;
}
.frameInner {
width: 200px;
position: relative;
background-color: #d9d9d9;
display: none;
}
.frameInner,
.rectangleDiv,
.rectangleGroup {
width: 400px;
border-radius: 5px;
max-width: 100%;
}
.rectangleGroup {
height: 10px;
background-color: #d9d9d9;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
.projectRemainingUntil {
align-self: stretch;
position: relative;
}
.container,
.days3,
.daysOfDaysFrame {
display: flex;
justify-content: flex-start;
}
.days3 {
width: 600px;
flex-direction: column;
align-items: flex-start;
gap: 5px 0;
}
.container,
.daysOfDaysFrame {
box-sizing: border-box;
max-width: 100%;
}
.daysOfDaysFrame {
flex: 1;
flex-direction: column;
align-items: flex-start;
padding: 0 0 31px;
gap: 20px 0;
min-width: 490px;
flex-shrink: 0;
font-size: 16px;
color: #777;
}
.container {
width: 1240px;
background-color: #fff;
border: 1px solid #7eacd3;
overflow: hidden;
flex-direction: row;
flex-wrap: wrap;
align-items: flex-end;
padding: 26px 21px 20px 19px;
row-gap: 20px;
text-align: left;
font-size: 20px;
color: #333;
}
@media screen and (max-width: 675px) {
.notificationText,
.notificationText1,
.text {
gap: 0 37px;
}
.daysOfDaysFrame,
.projectFrame {
min-width: 100%;
overflow-x: auto;
}
}
@media screen and (max-width: 450px) {
.currentPlan {
font-size: 16px;
}
.containerFrame {
flex-wrap: wrap;
}
}

3
src/views/SimproV2/Settings/index.js

@ -141,7 +141,7 @@ const Setting = ({ params }) => {
} else {
NotificationManager.error("Gagal Mengambil Data!!", "Failed");
}
};
}
const getDataRefferal = async (user_id, username, ktp_number) => {
const url = REFFERAL_GET_ID(user_id);
@ -181,7 +181,6 @@ const Setting = ({ params }) => {
});
}
return (
<div>
<NotificationContainer />

Loading…
Cancel
Save