Merge branch 'develop' into 'devops-staging'

Develop

See merge request empatnusabangsa/ppob/ppob-frontend!17
This commit is contained in:
Catur Bagaskara 2021-12-23 16:17:04 +00:00
commit fe81a3d81b
29 changed files with 1334 additions and 934 deletions

View File

@ -34,32 +34,6 @@ export const CategoryComponent = observer((props) => {
dataIndex: "name",
key: "name",
},
// {
// title: "Gangguan",
// dataIndex: "status",
// key: "status",
// render: (text, record) => (
// <Tag
// color={record?.status === "ACTIVE" ? "blue" : "#E3E8EE"}
// style={{color: "#4F566B"}}
// >
// {capitalize(record?.status)}
// </Tag>
// ),
// },
// {
// title: "Tersedia",
// dataIndex: "tersedia",
// key: "tersedia",
// render: (text, record) => (
// <Tag
// color={record?.status === "ACTIVE" ? "blue" : "#E3E8EE"}
// style={{color: "#4F566B"}}
// >
// {record?.status === "ACTIVE" ? " Ya" : "Tidak"}
// </Tag>
// ),
// },
{
title: "Action",
key: "action",
@ -95,10 +69,12 @@ export const CategoryComponent = observer((props) => {
if (idData !== "") {
modalLoader.setLoading(true);
try {
await store.category.update(idData, data);
message.success("Success Update Data Category");
const response =await store.category.update(idData, data);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Ubah Kategori")
: message.error("Gagal Ubah Kategori");
} catch (e) {
message.error("Failed Update Data Category");
message.error("Gagal Ubah Data Kategori");
}
modalLoader.setLoading(false);
store.category.visibleModalCategory = false;
@ -107,11 +83,13 @@ export const CategoryComponent = observer((props) => {
} else {
modalLoader.setLoading(true);
try {
await store.category.create(data);
message.success("Success Add New Category");
const response=await store.category.create(data);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Tambah Kategori")
: message.error("Gagal Tambah Kategori");
} catch (e) {
console.log(e, "apa errornya");
message.error("Failed Add Category");
message.error("Gagal Tambah Kategori");
}
modalLoader.setLoading(false);
store.category.visibleModalCategory = false;

View File

@ -52,10 +52,12 @@ export const CommissionComponent = observer((props) => {
const handleSubmit = async (data) => {
modalLoader.setLoading(true);
try {
await store.commission.update(idData, data);
message.success("Success Update Data Member");
const response=await store.commission.update(idData, data);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Ubah Komisi")
: message.error("Gagal Ubah Komisi");
} catch (e) {
message.error("Failed Update Data Member");
message.error("Gagal Ubah Komisi");
}
modalLoader.setLoading(false);
store.commission.visibleModalCommission = false;

View File

@ -1,11 +1,22 @@
import React, {useContext, useState} from "react";
import {Button, Divider, Form, Input, List, message, Modal, Space, Table, Tag,} from "antd";
import {observer} from "mobx-react-lite";
import {ExclamationCircleOutlined} from "@ant-design/icons";
import {useHistory} from "react-router-dom";
import {useStore} from "../utils/useStore";
import {LINKS} from "../routes/app";
import {ModalLoaderContext} from "../utils/modal";
import React, { useContext, useState } from "react";
import {
Button,
Divider,
Form,
Input,
List,
message,
Modal,
Space,
Table,
Tag,
} from "antd";
import { observer } from "mobx-react-lite";
import { ExclamationCircleOutlined } from "@ant-design/icons";
import { useHistory } from "react-router-dom";
import { useStore } from "../utils/useStore";
import { LINKS } from "../routes/app";
import { ModalLoaderContext } from "../utils/modal";
export const PartnerComponent = observer((props) => {
const store = useStore();
@ -151,6 +162,7 @@ export const PartnerComponent = observer((props) => {
? "Failed Change Partner Password"
: "Success Update Data Partner"
);
//await store.partner.getData()
} catch (e) {
modalLoader.setLoading(true);
@ -166,12 +178,14 @@ export const PartnerComponent = observer((props) => {
} else {
modalLoader.setLoading(true);
try {
await store.partner.create(data);
message.success("Success Add New Partner");
const response = await store.partner.create(data);
modalLoader.setLoading(false);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Tambah Partner")
: message.error("Gagal Tambah Partner");
} catch (e) {
console.log(e, "apa errornya");
message.error("Failed Add Partner");
message.error("Gagal Tambah Partner");
}
modalLoader.setLoading(false);
store.partner.visibleModalPartner = false;
@ -219,7 +233,7 @@ export const PartnerComponent = observer((props) => {
pageSize: store.partner.pageSize,
total: store.partner.total_data,
current: store.partner.page + 1,
style: {marginBottom: "1rem", marginRight: "1rem"},
style: { marginBottom: "1rem", marginRight: "1rem" },
}}
dataSource={store.partner.data}
style={{ padding: 0 }}

View File

@ -79,19 +79,17 @@ export const ProductComponent = observer((props) => {
currency: "IDR",
}).format(text),
},
// {
// title: "Gangguan",
// dataIndex: "status",
// key: "status",
// render: (text, record) => (
// <Tag
// color={record?.status === "ACTIVE" ? "blue" : "#E3E8EE"}
// style={{color: "#4F566B"}}
// >
// {capitalize(record?.status)}
// </Tag>
// ),
// },
{
title: "Supplier",
dataIndex: "supplier_name",
key: "supplier_name",
},
{
title: "Sub Category",
dataIndex: "sub_categories_name",
key: "sub_categories_name",
},
{
title: "Tersedia",
dataIndex: "tersedia",
@ -111,8 +109,7 @@ export const ProductComponent = observer((props) => {
render: (text, record) => (
<Button
onClick={async () => {
history.push(LINKS.PRODUCT_DETAIL.replace(":id", record.id));
//console.log(record.id)
history.push(LINKS.PRODUCT_DETAIL.replace(":id", record.product_id));
}}
>
Detail
@ -120,7 +117,8 @@ export const ProductComponent = observer((props) => {
),
},
];
if (store.authentication.userData.role !== "Admin") columns.pop();
if (store.authentication.userData.role !== "Admin") delete columns[4];
const deleteData = async (id) => {
try {
console.log(id);
@ -159,10 +157,12 @@ export const ProductComponent = observer((props) => {
if (idData !== "") {
modalLoader.setLoading(true);
try {
await store.product.update(idData, data);
message.success("Success Update Data Member");
const response=await store.product.update(idData, data);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Ubah Data Produk")
: message.error("Gagal Ubah Data Produk");
} catch (e) {
message.error("Failed Update Data Member");
message.error("Gagal Ubah Data Produk");
}
modalLoader.setLoading(false);
store.product.visibleModalProduct = false;
@ -171,11 +171,13 @@ export const ProductComponent = observer((props) => {
} else {
modalLoader.setLoading(true);
try {
await store.product.create(data);
message.success("Success Add New Member");
const response=await store.product.create(data);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Tambah Produk")
: message.error("Gagal Tambah Produk");
} catch (e) {
console.log(e, "apa errornya");
message.error("Failed Add Member");
message.error("Gagal Tambah Produk");
}
modalLoader.setLoading(false);
store.product.visibleModalProduct = false;
@ -289,7 +291,7 @@ export const ProductComponent = observer((props) => {
pageSize: store.product.pageSize,
total: store.product.total_data,
current: store.product.page + 1,
style: {marginBottom: "1rem", marginRight: "1rem"},
style: { marginBottom: "1rem", marginRight: "1rem" },
}}
dataSource={store.product.data}
style={{ padding: 0 }}

View File

@ -67,11 +67,13 @@ export const SubcategoryComponent = observer((props) => {
if (idData !== "") {
modalLoader.setLoading(true);
try {
await store.subcategory.update(idData, data);
const response=await store.subcategory.update(idData, data);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Ubah Data Sub Kategori")
: message.error("Gagal Ubah Data Sub Kategori");
//await getData();
message.success("Success Update Data Category");
} catch (e) {
message.error("Failed Update Data Category");
message.error("Gagal Ubah Data Sub Kategori");
}
modalLoader.setLoading(false);
store.subcategory.visibleModalSubcategory = false;
@ -80,11 +82,13 @@ export const SubcategoryComponent = observer((props) => {
} else {
modalLoader.setLoading(true);
try {
await store.subcategory.create(data);
message.success("Success Add New Category");
const response =await store.subcategory.create(data);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Tambah Sub Kategori")
: message.error("Gagal Tambah Sub Kategori");
} catch (e) {
console.log(e, "apa errornya");
message.error("Failed Add Category");
message.error("Gagal Tambah Sub Kategori");
}
modalLoader.setLoading(false);
store.subcategory.visibleModalSubcategory = false;

View File

@ -160,11 +160,13 @@ export const SupplierComponent = observer((props) => {
if (idData !== "") {
try {
modalLoader.setLoading(true);
await store.supplier.update(idData, data);
message.success("Success Update Data Member");
const response=await store.supplier.update(idData, data);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Ubah Data Supplier")
: message.error("Gagal Ubah Data Supplier");
} catch (e) {
modalLoader.setLoading(false);
message.error("Failed Update Data Member");
message.error("Gagal Ubah Data Supplie");
}
modalLoader.setLoading(false);
@ -174,11 +176,13 @@ export const SupplierComponent = observer((props) => {
} else {
try {
modalLoader.setLoading(true);
await store.supplier.create(data);
message.success("Success Add New Member");
const response=await store.supplier.create(data);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Tambah Supplier Baru")
: message.error("Gagal Tambah Supplier Baru");
} catch (e) {
console.log(e, "apa errornya");
message.error("Failed Add Member");
message.error("Gagal Tambah Supplier Baru");
}
modalLoader.setLoading(false);

View File

@ -120,15 +120,15 @@ export const DesktopLayout = observer(() => {
<Menu>
<Menu.Item key="home">
<Link to={LINKS.HOME}>
<HomeOutlined />
<span>Home</span>
<HomeOutlined/>
<span>Beranda</span>
</Link>
</Menu.Item>
{store.authentication.userData.role !== "Retail" && (
<Menu.Item key="membership">
<Link to={LINKS.MEMBERSHIP}>
<FileProtectOutlined />
<span>Membership</span>
<FileProtectOutlined/>
<span>Keanggotaan</span>
</Link>
</Menu.Item>
)}
@ -141,14 +141,14 @@ export const DesktopLayout = observer(() => {
>
<Menu.Item key="partner">
<Link to={LINKS.PARTNER}>
<HomeOutlined />
<span>Partner</span>
<HomeOutlined/>
<span>Rekanan</span>
</Link>
</Menu.Item>
<Menu.Item key="commision">
<Link to={LINKS.COMMISSION}>
<HomeOutlined />
<span>Commision</span>
<HomeOutlined/>
<span>Komisi</span>
</Link>
</Menu.Item>
<Menu.Item key="supplier">
@ -167,23 +167,23 @@ export const DesktopLayout = observer(() => {
>
<Menu.Item key="product">
<Link to={LINKS.PRODUCT}>
<DatabaseOutlined />
<span>Product</span>
<DatabaseOutlined/>
<span>Produk</span>
</Link>
</Menu.Item>
{store.authentication.userData.role === "Admin" && (
<Menu.Item key="category">
<Link to={LINKS.CATEGORY}>
<FileAddOutlined />
<span>Category</span>
<FileAddOutlined/>
<span>Kategori</span>
</Link>
</Menu.Item>
)}
{store.authentication.userData.role === "Admin" && (
<Menu.Item key="sub-category">
<Link to={LINKS.SUBCATEGORY}>
<FileSyncOutlined />
<span>Sub Category</span>
<FileSyncOutlined/>
<span>Sub Kategori</span>
</Link>
</Menu.Item>
)}
@ -192,29 +192,29 @@ export const DesktopLayout = observer(() => {
{store.authentication.userData.role !== "Admin" && (
<Menu.Item key="product">
<Link to={LINKS.PRODUCT}>
<DatabaseOutlined />
<span>Product</span>
<DatabaseOutlined/>
<span>Produk</span>
</Link>
</Menu.Item>
)}
{store.authentication.userData.role === "Retail" && (
<Menu.Item key="transaction">
<Link to={LINKS.TRANSACTION}>
<ShoppingCartOutlined />
<span>Transaction</span>
<ShoppingCartOutlined/>
<span>Transaksi</span>
</Link>
</Menu.Item>
)}
<SubMenu
key="payback-main"
icon={<ProfileOutlined/>}
title="Created"
title="Pembayaran"
>
{store.authentication.userData.role !== "Retail" && (
<Menu.Item key="payback-to-user">
<Link to={LINKS.PAYBACK}>
<PayCircleOutlined/>
<span>Confirmation</span>
<span>Konfirmasi</span>
</Link>
</Menu.Item>
)}
@ -222,7 +222,7 @@ export const DesktopLayout = observer(() => {
<Menu.Item key="payback-from-user">
<Link to={LINKS.PAYBACK_CREATED}>
<AlipayOutlined/>
<span>Created</span>
<span>Dibuat oleh Saya</span>
</Link>
</Menu.Item>
)}
@ -230,8 +230,8 @@ export const DesktopLayout = observer(() => {
{store.authentication.userData.role !== "Admin" && (
<Menu.Item key="profile">
<Link to={LINKS.PROFILE}>
<UserOutlined />
<span>Profile</span>
<UserOutlined/>
<span>Profil</span>
</Link>
</Menu.Item>
)}

View File

@ -2,7 +2,6 @@ import React, {useEffect, useState} from "react";
import {Menu} from "antd";
import {Link} from "react-router-dom";
import {
AlipayOutlined,
AppstoreOutlined,
DatabaseOutlined,
FileAddOutlined,
@ -11,7 +10,6 @@ import {
HomeOutlined,
MenuUnfoldOutlined,
MoneyCollectOutlined,
PayCircleOutlined,
ProfileOutlined,
ProjectOutlined,
ShoppingCartOutlined,
@ -52,14 +50,14 @@ export const MenuList = observer((props) => {
<Menu.Item key="home">
<Link to={LINKS.HOME}>
<HomeOutlined />
<span>Home</span>
<span>Beranda</span>
</Link>
</Menu.Item>
{store.authentication.userData.role !== "Retail" && (
<Menu.Item key="membership">
<Link to={LINKS.MEMBERSHIP}>
<FileProtectOutlined />
<span>Membership</span>
<span>Keanggotaan</span>
</Link>
</Menu.Item>
)}
@ -68,13 +66,13 @@ export const MenuList = observer((props) => {
<Menu.Item key="partner">
<Link to={LINKS.PARTNER}>
<ProjectOutlined />
<span>Partner</span>
<span>Rekanan</span>
</Link>
</Menu.Item>
<Menu.Item key="commision">
<Link to={LINKS.COMMISSION}>
<MoneyCollectOutlined />
<span>Commission</span>
<span>Komisi</span>
</Link>
</Menu.Item>
<Menu.Item key="supplier">
@ -90,14 +88,14 @@ export const MenuList = observer((props) => {
<Menu.Item key="product">
<Link to={LINKS.PRODUCT}>
<DatabaseOutlined />
<span>Product</span>
<span>Produk</span>
</Link>
</Menu.Item>
{store.authentication.userData.role === "Admin" && (
<Menu.Item key="category">
<Link to={LINKS.CATEGORY}>
<FileAddOutlined />
<span>Category</span>
<span>Kategori</span>
</Link>
</Menu.Item>
)}
@ -105,7 +103,7 @@ export const MenuList = observer((props) => {
<Menu.Item key="sub-category">
<Link to={LINKS.SUBCATEGORY}>
<FileSyncOutlined />
<span>Sub Category</span>
<span>Sub Kategori</span>
</Link>
</Menu.Item>
)}
@ -115,7 +113,7 @@ export const MenuList = observer((props) => {
<Menu.Item key="retail">
<Link to={LINKS.PRODUCT}>
<DatabaseOutlined />
<span>Product</span>
<span>Produk</span>
</Link>
</Menu.Item>
)}
@ -123,24 +121,24 @@ export const MenuList = observer((props) => {
<Menu.Item key="transaction">
<Link to={LINKS.TRANSACTION}>
<ShoppingCartOutlined />
<span>Transaction</span>
<span>Transaksi</span>
</Link>
</Menu.Item>
)}
<SubMenu key="payback-main" icon={<ProfileOutlined />} title="Payback">
<SubMenu key="payback-main" icon={<ProfileOutlined />} title="Pembayaran">
{store.authentication.userData.role !== "Retail" && (
<Menu.Item key="payback-to-user">
<Link to={LINKS.PAYBACK}>
<PayCircleOutlined/>
<span>Confirmation</span>
<FileProtectOutlined/>
<span>Konfirmasi</span>
</Link>
</Menu.Item>
)}
{store.authentication.userData.role !== "Admin" && (
<Menu.Item key="payback-from-user">
<Link to={LINKS.PAYBACK_CREATED}>
<AlipayOutlined/>
<span>Created</span>
<FileProtectOutlined/>
<span>Dibuat oleh Saya</span>
</Link>
</Menu.Item>
)}
@ -148,17 +146,11 @@ export const MenuList = observer((props) => {
{store.authentication.userData.role !== "Admin" && (
<Menu.Item key="profile">
<Link to={LINKS.PROFILE}>
<UserOutlined />
<span>Profile</span>
<UserOutlined/>
<span>Profil</span>
</Link>
</Menu.Item>
)}
{/*<Menu.Item key="about">*/}
{/* <Link to={'/app/about'}>*/}
{/* <CalendarOutlined/>*/}
{/* <span>About</span>*/}
{/* </Link>*/}
{/*</Menu.Item>*/}
<Menu.Divider style={{ background: "transparent", paddingTop: 15 }} />
</Menu>
);

View File

@ -40,7 +40,7 @@ export const Partner = observer(() => {
},
{
route: LINKS.PARTNER,
name: <span style={{fontWeight: 'bold'}}>Partner</span>,
name: <span style={{fontWeight: 'bold'}}>Rekanan</span>,
},
];
@ -49,21 +49,21 @@ export const Partner = observer(() => {
<BreadcumbComponent data={routeData}/>
<Card>
<Row style={{marginBottom: 20}}>
<Col span={12}>
{/* <Button>
{/* <Col span={12}>
<Button>
<FilterOutlined/>
Filter
</Button> */}
</Col>
<Col span={12} style={{textAlign: "right"}}>
<Search
</Button>
</Col> */}
<Col span={24} style={{textAlign: "right"}}>
{/* <Search
placeholder="input search text"
style={{
width: store.ui.mediaQuery.isMobile ? 160 : 200,
marginRight: store.ui.mediaQuery.isMobile ? 0 : 10,
marginBottom: store.ui.mediaQuery.isMobile ? 10 : 0,
}}
/>
/> */}
<Button onClick={() => store.partner.visibleModalPartner = true}>
<PlusSquareOutlined/> New
</Button>

View File

@ -71,7 +71,7 @@ export const Supplier = observer(() => {
</Button>
</Col> */}
<Col span={24} style={{ textAlign: "right" }}>
<Search
{/* <Search
placeholder="input search text"
style={{
width: store.ui.mediaQuery.isMobile ? 160 : 200,
@ -79,7 +79,7 @@ export const Supplier = observer(() => {
marginBottom: store.ui.mediaQuery.isMobile ? 10 : 0,
}}
onSearch={(value) => console.log(value)}
/>
/> */}
<Button
onClick={() => (store.supplier.visibleModalSupplier = true)}
>

View File

@ -1,151 +1,279 @@
import React, {useContext, useEffect} from "react";
import {Button, Card, Col, Row, Table, Typography} from "antd";
import React, {useContext, useEffect, useState} from "react";
import {Button, Card, Col, message, Row, Space, Table, Tag, Typography,} from "antd";
import {BreadcumbComponent} from "../../component/BreadcumbComponent";
import {LINKS} from "../../routes/app";
import {useStore} from "../../utils/useStore";
import {observer} from "mobx-react-lite";
import {FilterOutlined} from "@ant-design/icons";
import {format, parseISO} from "date-fns";
import {ModalLoaderContext} from "../../utils/modal";
import {useParams} from "react-router-dom";
import {MembershipModal} from "./MembershipModal";
const {Title, Text} = Typography;
export const DetailUser = observer(() => {
const store = useStore();
const modalLoader = useContext(ModalLoaderContext);
const { id } = useParams();
const {id} = useParams();
const [visibleModal, setVisibleModal] = useState(false);
const [isVisibleTopUpModal, setIsVisibleTopUpModal] = useState(false);
const [destination, setDestination] = useState(null);
const [initialData, setInitialData] = useState({});
const [confirmLoading, setConfirmLoading] = useState(false);
useEffect(() => {
(async () => {
modalLoader.setLoading(true);
await getData();
modalLoader.setLoading(false);
})();
return () => {
store.membership.dataDetail = {};
store.transaction.dataHistoryTopUp = [];
};
}, []);
const getData = async () => {
const isAdmin = store.authentication.userData.role === "Admin";
await Promise.allSettled([
store.transaction.getDataHistoryTopUp(id),
store.membership.getDetail(id),
store.role.getData(isAdmin)
]);
};
const changeStatus = async (id, isActive) => {
const status = isActive ? "inactive" : "active";
const status2 = isActive ? "Inactivating" : "Activating";
try {
modalLoader.setLoading(true);
const response = await store.membership.changeStatus(id, status);
modalLoader.setLoading(false);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success(`Success ${status2} Membership`)
: message.error(`Failed ${status2} Membership`);
await getData();
} catch (err) {
modalLoader.setLoading(false);
message.error(`Failed ${status2} Membership`);
}
};
const onSubmit = async (data) => {
data.superior = true;
setConfirmLoading(true);
modalLoader.setLoading(true);
try {
let response;
if (initialData.isChangePassword) {
response = await store.membership.changePassword(initialData.id, data);
} else {
response = await store.membership.update(initialData.id, data);
}
setVisibleModal(false);
if (response?.body?.statusCode === 200) {
message.success(
initialData.isChangePassword
? "Success Change Member Password"
: "Success Update Data Member");
} else {
message.error(
initialData.isChangePassword
? "Failed Change Member Password"
: "Failed Update Data Member");
}
await getData();
} catch (e) {
modalLoader.setLoading(false);
message.error(
initialData.isChangePassword
? "Failed Update Member Password"
: "Failed Update Data Member"
);
}
modalLoader.setLoading(false);
setConfirmLoading(false);
};
const columns = [
{
title: "Amount",
dataIndex: "amount",
key: "amount",
},
{
title: "Transaction Date",
dataIndex: "transaction_date",
key: "transaction_date",
render: (text, record) => {
return (
<Text>
{format(parseISO(record.transaction_date), "dd MMMM yyyy ")}
</Text>
);
},
},
{
title: "Status",
dataIndex: "isActive",
key: "isActive",
render: (text, record) => (
<Tag
color={store.membership.dataDetail.isActive === true ? "processing" : "#E3E8EE"}
style={{color: "#4F566B"}}
>
{store.membership.dataDetail.isActive === true ? " ACTIVE" : "INACTIVE"}
</Tag>
),
},
];
const routeData = [
{
route: LINKS.HOME,
name: "Home",
},
{
route: LINKS.MEMBERSHIP,
name: <span style={{ fontWeight: "bold" }}>Keanggotaan</span>,
},
{
route: LINKS.USER_DETAIL,
name: <span style={{fontWeight: 'bold'}}>Detail User</span>,
name: <span style={{ fontWeight: "bold" }}>Detail Anggota</span>,
},
];
console.log(id)
useEffect(() => {
(async () => {
modalLoader.setLoading(true);
await Promise.allSettled([
store.authentication.getProfile(),
store.transaction.getDataHistoryTopUp(id),
store.transaction.getDataHistoryTransaction(),
]);
modalLoader.setLoading(false);
})()
}, []);
const columns = [
{
title: 'Markup Price',
dataIndex: 'mark_up_price',
key: 'mark_up_price',
width: '20%',
},
{
title: 'Name',
dataIndex: 'name',
key: 'name',
width: '50%',
},
{
title: 'Transaction Date',
dataIndex: 'created_at',
key: 'created_at',
render: (text, record) => {
return (
<Text>{format(parseISO(record.created_at), 'dd MMMM yyyy HH:mm')}</Text>
)
},
},
]
const styleSaldoTitle = store.ui.mediaQuery.isDesktop ? {
display: "flex",
justifyContent: "center"
} : {fontSize: "0.75rem"};
const styleSaldoContent = store.ui.mediaQuery.isDesktop ? {
fontSize: '1.25rem',
display: "flex",
justifyContent: "center"
} : null;
return (
<div className={["ppob-container"].join(" ")}>
<BreadcumbComponent data={routeData}/>
<BreadcumbComponent data={routeData} />
<Card>
<Title strong>Detail User</Title>
<Row style={{marginBottom: 20}}>
<Row style={{ marginBottom: 20 }}>
<Col lg={12} xs={24}>
<Row>
<Col span={12}>
<Text strong>Name</Text>
</Col>
<Col span={12}>
<Text>{store.transaction.data.name}</Text>
<Text>{store.membership.dataDetail.userDetail?.name}</Text>
</Col>
<Col span={12}>
<Text strong>Username</Text>
</Col>
<Col span={12}>
<Text>{store.membership.dataDetail.username}</Text>
</Col>
<Col span={12}>
<Text strong>Role</Text>
</Col>
<Col span={12}>
<Text>{store.authentication.profileData?.userDetail?.phone_number}</Text>
<Text>{store.membership.dataDetail.roles?.name}</Text>
</Col>
<Col span={12}>
<Text strong>Saldo Supplier</Text>
<Text strong>Phone Number</Text>
</Col>
<Col span={12}>
<Text>{store.authentication.profileData?.username}</Text>
</Col>
<Col span={12}>
<Text strong>Saldo System</Text>
</Col>
<Col span={12}>
<Text>{store.authentication.profileData.roles?.name}</Text>
<Text>
{store.membership.dataDetail.userDetail?.phone_number}
</Text>
</Col>
<Col span={12}>
<Text strong>Status</Text>
</Col>
<Col span={12}>
<Text>{store.authentication.profileData.superior?.username}</Text>
<Text>
{store.membership.dataDetail.isActive === true
? "Aktif"
: "Inaktif"}
</Text>
</Col>
</Row>
</Col>
<Col lg={12} xs={24}>
<Row justify={"center"}>
<Col lg={24} xs={12}>
<Title strong level={3} style={styleSaldoTitle}>Saldo</Title>
</Col>
<Col lg={24} xs={12}>
<Text style={styleSaldoContent}>{store.authentication.profileData?.wallet}</Text>
</Col>
</Row>
<Title strong level={3}>Action User Detail</Title>
<Space
size="middle"
align={"center"}
wrap={true}
style={{textAlign: 'center'}}
>
{store.authentication.userData.role === "Admin" &&
<Button
type={store.membership.dataDetail.isActive === true ? "danger" : "primary"}
onClick={() => changeStatus(store.membership.dataDetail.id, store.membership.dataDetail.isActive)}
>
{store.membership.dataDetail.isActive === true ? "Inactive" : "Active"}
</Button>
}
{store.authentication.userData.role === "Admin" &&
<Button
onClick={() => {
setInitialData({
id: store.membership.dataDetail.id,
name: store.membership.dataDetail.userDetail.name,
username: store.membership.dataDetail.username,
phone_number: store.membership.dataDetail.userDetail.phone_number,
roleId: store.membership.dataDetail.roles.id,
isChangePassword: false,
});
setVisibleModal(true);
}}
>
Edit
</Button>
}
{store.authentication.userData.role === "Admin" &&
<Button
onClick={() => {
setInitialData({
id: store.membership.dataDetail.id,
name: store.membership.dataDetail.userDetail.name,
username: store.membership.dataDetail.username,
phone_number: store.membership.dataDetail.userDetail.phone_number,
roleId: store.membership.dataDetail.roles.id,
isChangePassword: true,
});
setVisibleModal(true);
}}
>
Ganti Password
</Button>
}
</Space>
</Col>
</Row>
<Row>
<Col span={24}>
<div>
<Title strong level={3}>History Top Up</Title>
<Button style={{marginBottom: '1rem'}} onClick={() => {
console.log('clicked filter')
}}>
<FilterOutlined/>
Filter
</Button>
<Title strong level={3}>
History Top Up
</Title>
<Table
columns={columns}
dataSource={store.transaction.dataHistoryTransaction}
dataSource={store.transaction.dataHistoryTopUp}
bordered
/>
</div>
</Col>
</Row>
<div/>
<div />
</Card>
<MembershipModal
visible={visibleModal}
confirmLoading={confirmLoading}
initialData={initialData}
onCreate={async (data) => {
onSubmit(data);
}}
onCancel={() => {
setInitialData({});
setVisibleModal(false);
}}
/>
</div>
)
);
});

View File

@ -1,32 +1,28 @@
import React, {useContext, useEffect, useState} from "react";
import React, { useContext, useEffect, useState } from "react";
import {
Button,
Card,
Col,
Divider,
Form,
Input,
InputNumber,
List,
message,
Modal,
Row,
Select,
Space,
Table,
Tag,
} from "antd";
import {useStore} from "../../utils/useStore";
import {observer} from "mobx-react-lite";
import {DownloadOutlined, PlusSquareOutlined} from "@ant-design/icons";
import {MembershipModal} from "./MembershipModal";
import {BreadcumbComponent} from "../../component/BreadcumbComponent";
import {LINKS} from "../../routes/app";
import {useHistory} from "react-router-dom";
import {ModalLoaderContext} from "../../utils/modal";
import { useStore } from "../../utils/useStore";
import { observer } from "mobx-react-lite";
import { DownloadOutlined, PlusSquareOutlined } from "@ant-design/icons";
import { MembershipModal } from "./MembershipModal";
import { BreadcumbComponent } from "../../component/BreadcumbComponent";
import { LINKS } from "../../routes/app";
import { useHistory } from "react-router-dom";
import { ModalLoaderContext } from "../../utils/modal";
const {Search} = Input;
const {Option} = Select;
export const Membership = observer(() => {
const history = useHistory();
const [form] = Form.useForm();
@ -147,30 +143,11 @@ export const Membership = observer(() => {
currency: "IDR",
}).format(text),
},
{
title: "Status",
dataIndex: "isActive",
key: "isActive",
render: (text, record) => (
<Tag
color={record?.isActive === true ? "processing" : "#E3E8EE"}
style={{ color: "#4F566B" }}
>
{record?.isActive === true ? " ACTIVE" : "INACTIVE"}
</Tag>
),
},
{
title: "Action",
key: "action",
render: (text, record) => (
<Space size="middle">
{store.authentication.userData.role === "Admin" && <Button
type={record?.isActive === true ? "danger" : "primary"}
onClick={() => changeStatus(record?.id, record?.isActive)}
>
{record?.isActive === true ? "Inactive" : "Active"}
</Button>}
<Button
onClick={() => {
setDestination(record?.id);
@ -178,41 +155,11 @@ export const Membership = observer(() => {
setIsVisibleTopUpModal(true);
}}
>
<DownloadOutlined/> Top Up Saldo
<DownloadOutlined /> Top Up Saldo
</Button>
{store.authentication.userData.role === "Admin" && <Button
onClick={() => {
let record2 = record;
delete record2.password;
record2.isChangePassword = false;
setInitialData({
...record2,
// roleId: record.roles.id,
});
setVisibleModal(true);
}}
>
Edit
</Button>}
{store.authentication.userData.role === "Admin" && <Button
onClick={() => {
let record2 = record;
delete record2.password;
record2.isChangePassword = true;
setInitialData({
...record2,
// roleId: record.roles.id,
});
setVisibleModal(true);
}}
>
Ganti Password
</Button>}
<Button
onClick={async () => {
await store.transaction.getDataHistoryTopUp(record.id)
await store.transaction.getDataHistoryTopUp(record.id);
history.push(LINKS.USER_DETAIL.replace(":id", record.id));
console.log(record.id);
}}
@ -230,8 +177,8 @@ export const Membership = observer(() => {
name: "Home",
},
{
route: "/app/membership",
name: <span style={{ fontWeight: "bold" }}>Membership</span>,
route: LINKS.MEMBERSHIP,
name: <span style={{ fontWeight: "bold" }}>Keanggotaan</span>,
},
];
@ -264,12 +211,14 @@ export const Membership = observer(() => {
setConfirmLoading(true);
modalLoader.setLoading(true);
try {
await store.membership.create(data);
message.success("Success Add New Member");
const response = await store.membership.create(data);
response?.body?.statusCode === 201 || response?.body?.statusCode === 200
? message.success("Berhasil Tambah Member Baru")
: message.error("Gagal Tambah Member Baru");
await getData();
} catch (e) {
console.log(e, "apa errornya");
message.error("Failed Add Member");
message.error("Gagal Tambah Member Baru");
}
modalLoader.setLoading(false);
setConfirmLoading(false);
@ -291,14 +240,14 @@ export const Membership = observer(() => {
</Button> */}
</Col>
<Col span={12} style={{ textAlign: "right" }}>
<Search
{/* <Search
placeholder="input search text"
style={{
width: store.ui.mediaQuery.isMobile ? 160 : 200,
marginRight: store.ui.mediaQuery.isMobile ? 0 : 10,
marginBottom: store.ui.mediaQuery.isMobile ? 10 : 0,
}}
/>
/> */}
<Button
onClick={() => {
setInitialData({});
@ -318,7 +267,7 @@ export const Membership = observer(() => {
bordered
pagination={{
pageSize: store.membership.pageSize,
total: store.membership.total_data,
total: store.membership.totalData,
current: store.membership.page + 1,
showSizeChanger: true,
simple: false,
@ -347,9 +296,9 @@ export const Membership = observer(() => {
modalLoader.setLoading(false);
},
pageSize: store.membership.pageSize,
total: store.membership.total_data,
total: store.membership.totalData,
current: store.membership.page + 1,
style: {marginBottom: "1rem", marginRight: "1rem"},
style: { marginBottom: "1rem", marginRight: "1rem" },
}}
dataSource={store.membership.data}
style={{ padding: 0 }}
@ -383,6 +332,29 @@ export const Membership = observer(() => {
Saldo System : {item.coa.amount}
</small>{" "}
<br />
<Button
style={{marginRight:10}}
onClick={() => {
setDestination(item?.id);
console.log(item?.id);
setIsVisibleTopUpModal(true);
}}
>
<DownloadOutlined /> Top Up Saldo
</Button>
<Button
onClick={async () => {
await store.transaction.getDataHistoryTopUp(
item.id
);
history.push(
LINKS.USER_DETAIL.replace(":id", item.id)
);
console.log(item.id);
}}
>
Detail
</Button>
</p>
</div>
}
@ -394,7 +366,7 @@ export const Membership = observer(() => {
margin: 0,
}}
>
<Button
{/* <Button
type={
item?.isActive === true ? "danger" : "primary"
}
@ -403,7 +375,7 @@ export const Membership = observer(() => {
}
>
{item?.isActive === true ? "Inactive" : "Active"}
</Button>
</Button> */}
</p>
</div>
</List.Item>

View File

@ -32,11 +32,7 @@ export const MembershipModal = ({
form
.validateFields()
.then((values) => {
let input = values;
if (initialData.id)
input.username = initialData.username;
onCreate(input);
onCreate(values);
form.resetFields();
})
.catch((info) => {
@ -55,18 +51,18 @@ export const MembershipModal = ({
<Form.Item
name="name"
label="Name"
rules={[{ required: true, message: "Please input Name!" }]}
rules={[{required: true, message: "Please input Name!"}]}
>
<Input />
<Input/>
</Form.Item>
)}
{!initialData.id && (
<Form.Item
name="username"
label="Username"
rules={[{ required: true, message: "Please input Username!" }]}
rules={[{required: true, message: "Please input Username!"}]}
>
<Input />
<Input/>
</Form.Item>
)}
{((initialData.id && initialData.isChangePassword) ||
@ -74,7 +70,7 @@ export const MembershipModal = ({
<Form.Item
name="password"
label="Password"
rules={[{ required: false, message: "Please input password!" }]}
rules={[{required: false, message: "Please input password!"}]}
>
<Input.Password/>
</Form.Item>
@ -84,9 +80,9 @@ export const MembershipModal = ({
<Form.Item
name="phone_number"
label="Phone Number"
rules={[{ required: true, message: "Please input Phone Number!" }]}
rules={[{required: true, message: "Please input Phone Number!"}]}
>
<Input />
<Input/>
</Form.Item>
)}
{((initialData.id && !initialData.isChangePassword) ||
@ -94,7 +90,7 @@ export const MembershipModal = ({
<Form.Item
name="roleId"
label="Role"
rules={[{ required: true, message: "Please input role id!" }]}
rules={[{required: true, message: "Please input role id!"}]}
>
<Select>
{store.role.data.map((item) => (

View File

@ -1,16 +1,36 @@
import React, {useContext, useEffect} from "react";
import {Button, Card, Col, Divider, Image, Input, List, message, Modal, Row, Space, Table, Tag,} from "antd";
import {useStore} from "../../utils/useStore";
import {observer} from "mobx-react-lite";
import {CheckCircleOutlined, CheckOutlined, CloseOutlined, FilterOutlined, StopOutlined,} from "@ant-design/icons";
import {BreadcumbComponent} from "../../component/BreadcumbComponent";
import {LINKS} from "../../routes/app";
import {ModalLoaderContext} from "../../utils/modal";
import {appConfig} from "../../config/app";
import {capitalize} from "lodash";
import {PAYBACK_STATUS} from "../../constants/payback";
import React, { useContext, useEffect } from "react";
import {
Button,
Card,
Col,
Divider,
Image,
Input,
List,
message,
Modal,
Row,
Space,
Table,
Tag,
} from "antd";
import { useStore } from "../../utils/useStore";
import { observer } from "mobx-react-lite";
import {
CheckCircleOutlined,
CheckOutlined,
CloseOutlined,
FilterOutlined,
StopOutlined,
} from "@ant-design/icons";
import { BreadcumbComponent } from "../../component/BreadcumbComponent";
import { LINKS } from "../../routes/app";
import { ModalLoaderContext } from "../../utils/modal";
import { appConfig } from "../../config/app";
import { capitalize } from "lodash";
import { PAYBACK_STATUS } from "../../constants/payback";
const {Search} = Input;
const { Search } = Input;
export const Payback = observer(() => {
const store = useStore();
@ -48,7 +68,7 @@ export const Payback = observer(() => {
render: (text, record) => (
<Image
src={`${appConfig.apiUrl}/config/image/${text}`}
style={{width: '5vw'}}
style={{ width: "5vw" }}
alt={record.id}
/>
),
@ -57,7 +77,7 @@ export const Payback = observer(() => {
title: "Amount",
dataIndex: "amount",
key: "amount",
width: '20%',
width: "20%",
render: (text) =>
new Intl.NumberFormat("id-ID", {
style: "currency",
@ -68,15 +88,15 @@ export const Payback = observer(() => {
title: "Action",
dataIndex: "amount",
key: "action",
width: '10%',
render: (text, record) => (
PAYBACK_STATUS[record.status] === PAYBACK_STATUS[0] ?
width: "10%",
render: (text, record) =>
PAYBACK_STATUS[record.status] === PAYBACK_STATUS[0] ? (
<Space size="middle">
<Button
onClick={async () => {
Modal.confirm({
title: `Are you sure Accept this submission?`,
icon: <CheckOutlined/>,
icon: <CheckOutlined />,
okText: "Accept",
cancelText: "Cancel",
okType: "primary",
@ -86,9 +106,9 @@ export const Payback = observer(() => {
onCancel() {
console.log("Cancel");
},
})
});
}}
icon={<CheckCircleOutlined/>}
icon={<CheckCircleOutlined />}
style={{
backgroundColor: "#1bb91d",
color: "#fff",
@ -101,7 +121,7 @@ export const Payback = observer(() => {
onClick={async () => {
Modal.confirm({
title: `Are you sure Reject this submission?`,
icon: <StopOutlined/>,
icon: <StopOutlined />,
okText: "Reject",
cancelText: "Cancel",
okType: "primary",
@ -111,10 +131,9 @@ export const Payback = observer(() => {
onCancel() {
console.log("Cancel");
},
})
});
}}
icon={<CloseOutlined/>}
icon={<CloseOutlined />}
style={{
backgroundColor: "#ff1c1c",
color: "#fff",
@ -123,10 +142,15 @@ export const Payback = observer(() => {
>
Reject
</Button>
</Space> :
</Space>
) : (
<Tag
color={PAYBACK_STATUS[record.status] === PAYBACK_STATUS[3] ? "cyan" : "red"}
style={{color: "#4F566B"}}
color={
PAYBACK_STATUS[record.status] === PAYBACK_STATUS[3]
? "cyan"
: "red"
}
style={{ color: "#4F566B" }}
>
{PAYBACK_STATUS[record.status]}
</Tag>
@ -143,7 +167,7 @@ export const Payback = observer(() => {
},
{
route: LINKS.PAYBACK,
name: <span style={{fontWeight: "bold"}}>Payback Confirmation</span>,
name: <span style={{ fontWeight: "bold" }}>Konfirmasi Pembayaran</span>,
},
];
@ -165,25 +189,25 @@ export const Payback = observer(() => {
return (
<div className={["ppob-container"].join(" ")}>
<BreadcumbComponent data={routeData}/>
<BreadcumbComponent data={routeData} />
<Card>
<div>
<Row style={{marginBottom: 20}}>
<Row style={{ marginBottom: 20 }}>
<Col span={12}>
<Button>
<FilterOutlined/>
<FilterOutlined />
Filter
</Button>
</Col>
<Col span={12} style={{textAlign: "right"}}>
<Search
<Col span={12} style={{ textAlign: "right" }}>
{/* <Search
placeholder="input search text"
style={{
width: store.ui.mediaQuery.isMobile ? 160 : 200,
marginRight: store.ui.mediaQuery.isMobile ? 0 : 10,
marginBottom: store.ui.mediaQuery.isMobile ? 10 : 0,
}}
/>
/> */}
</Col>
</Row>
{store.ui.mediaQuery.isDesktop && (
@ -198,7 +222,7 @@ export const Payback = observer(() => {
total: store.payback.totalDataConfirmation,
current: store.payback.pageSizeConfirmation + 1,
showSizeChanger: true,
simple: false
simple: false,
}}
onChange={async (page) => {
let pageNumber = page.current;
@ -226,10 +250,10 @@ export const Payback = observer(() => {
pageSize: store.payback.pageSizeConfirmation,
total: store.payback.totalDataConfirmation,
current: store.payback.pageConfirmation + 1,
style: {marginBottom: "1rem", marginRight: "1rem"},
style: { marginBottom: "1rem", marginRight: "1rem" },
}}
dataSource={store.payback.dataConfirmation}
style={{padding: 0}}
style={{ padding: 0 }}
renderItem={(item) => {
return (
<div>
@ -250,11 +274,11 @@ export const Payback = observer(() => {
title={item.name}
description={
<div style={{}}>
<Image src={item.picture} preview={false}/>
<Image src={item.picture} preview={false} />
</div>
}
/>
<div style={{marginRight: 16}}>
<div style={{ marginRight: 16 }}>
<p
style={{
fontSize: 9,
@ -265,7 +289,7 @@ export const Payback = observer(() => {
</p>
</div>
</List.Item>
<Divider plain style={{margin: 0}}/>
<Divider plain style={{ margin: 0 }} />
</div>
);
}}

View File

@ -84,7 +84,7 @@ export const PaybackCreated = observer(() => {
},
{
route: LINKS.PAYBACK_CREATED,
name: <span style={{fontWeight: "bold"}}>Payback Created</span>,
name: <span style={{fontWeight: "bold"}}>Buat Pembayaran</span>,
},
];
@ -101,14 +101,14 @@ export const PaybackCreated = observer(() => {
</Button>
</Col>
<Col span={12} style={{textAlign: "right"}}>
<Search
{/* <Search
placeholder="input search text"
style={{
width: store.ui.mediaQuery.isMobile ? 160 : 200,
marginRight: store.ui.mediaQuery.isMobile ? 0 : 10,
marginBottom: store.ui.mediaQuery.isMobile ? 10 : 0,
}}
/>
/> */}
{store.authentication.userData.role !== "Admin" && (
<Button
onClick={() => {

View File

@ -3,7 +3,6 @@ import {Form, InputNumber, message, Modal, Upload,} from "antd";
import {useStore} from "../../utils/useStore";
import {LoadingOutlined, PlusOutlined} from "@ant-design/icons";
import {ModalLoaderContext} from "../../utils/modal";
import {http} from "../../utils/http";
import {appConfig} from "../../config/app";
export const PaybackModal = ({initialData}) => {
@ -32,7 +31,7 @@ export const PaybackModal = ({initialData}) => {
const uploadHandler = async (args) => {
const file = args.file;
const res = await http.upload(file);
const res = await store.payback.uploadImages(file);
setImage(`${appConfig.apiUrl}/config/image/${res.body.filename}`);
setResponseFilename(res.body.filename);
setFileList([{

View File

@ -41,7 +41,7 @@ export const Category = observer(() => {
},
{
route: LINKS.CATEGORY,
name: <span style={{ fontWeight: "bold" }}>Category</span>,
name: <span style={{ fontWeight: "bold" }}>Kategori</span>,
},
];
@ -50,21 +50,21 @@ export const Category = observer(() => {
<BreadcumbComponent data={routeData} />
<Card>
<Row style={{ marginBottom: 20 }}>
<Col span={12}>
{/* <Col span={12}>
<Button>
<FilterOutlined />
Filter
</Button>
</Col>
<Col span={12} style={{ textAlign: "right" }}>
<Search
</Col> */}
<Col span={24} style={{ textAlign: "right" }}>
{/* <Search
placeholder="input search text"
style={{
width: store.ui.mediaQuery.isMobile ? 160 : 200,
marginRight: store.ui.mediaQuery.isMobile ? 0 : 10,
marginBottom: store.ui.mediaQuery.isMobile ? 10 : 0,
}}
/>
/> */}
<Button
onClick={() => (store.category.visibleModalCategory = true)}
>

View File

@ -1,26 +1,30 @@
import React, { useContext, useEffect } from "react";
import { Button, Card, Col, Input, message, Row, Upload } from "antd";
import {
FilterOutlined,
PlusSquareOutlined,
UploadOutlined,
} from "@ant-design/icons";
import { BreadcumbComponent } from "../../component/BreadcumbComponent";
import { useStore } from "../../utils/useStore";
import { observer } from "mobx-react-lite";
import { ProductComponent } from "../../component/ProductComponent";
import { LINKS } from "../../routes/app";
import { ModalLoaderContext } from "../../utils/modal";
import React, {useContext, useEffect, useState} from "react";
import {Button, Card, Col, Form, Input, message, Modal, Row, Select, Upload} from "antd";
import {FilterOutlined, PlusOutlined, UploadOutlined,} from "@ant-design/icons";
import {BreadcumbComponent} from "../../component/BreadcumbComponent";
import {useStore} from "../../utils/useStore";
import {observer} from "mobx-react-lite";
import {ProductComponent} from "../../component/ProductComponent";
import {LINKS} from "../../routes/app";
import {ModalLoaderContext} from "../../utils/modal";
const { Search } = Input;
const {Search} = Input;
const {Option} = Select;
export const Product = observer(() => {
const store = useStore();
const modalLoader = useContext(ModalLoaderContext);
const [loading, setLoading] = useState(false);
const [visibleModalUpload, setVisibleModalUpload] = useState(false);
const [excel, setExcel] = useState("");
const [fileList, setFileList] = useState([]);
const [form] = Form.useForm();
useEffect(() => {
const init = async () => {
try {
store.supplier.page = 0;
store.supplier.pageSize = 1000;
modalLoader.setLoading(true);
await Promise.allSettled([
store.supplier.getData(),
@ -40,6 +44,10 @@ export const Product = observer(() => {
};
init();
return () => {
store.supplier.pageSize = 10;
};
}, []);
const routeData = [
@ -49,22 +57,112 @@ export const Product = observer(() => {
},
{
route: LINKS.PRODUCT,
name: <span style={{ fontWeight: "bold" }}>Product</span>,
name: <span style={{fontWeight: "bold"}}>Produk</span>,
},
];
const beforeUpload = (file) => {
let isLt2M;
let allowedFile = [
"text/csv", "application/csv",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"application/vnd.ms-excel.sheet.binary.macroEnabled.12",
"application/vnd.ms-excel",
"application/vnd.ms-excel.sheet.macroEnabled.12"
];
let isValid = allowedFile.includes(file.type);
if (!isValid) {
message.error("You can only upload Excel file!");
}
isLt2M = file.size / 1024 / 1024 < 10;
if (!isLt2M) {
message.error("File must smaller than 10MB!");
}
return isValid && isLt2M ? true : Upload.LIST_IGNORE;
};
const uploadHandler = async (args) => {
const file = args.file;
try {
const response = await store.product.uploadExcel(file);
if (response.status === 201) {
message.success("Success upload excel!");
} else {
message.error("Failed upload excel!");
}
setFileList([{
uid: '-1',
name: response.body.filename,
status: 'done',
url: '',
}]);
setExcel(response.body.filename);
} catch (e) {
setLoading(false);
message.error("Failed upload excel!");
}
};
const handleChange = (info) => {
if (info.file.status === 'uploading') {
setLoading(true);
} else {
setLoading(false)
}
};
const handleUploadProduct = async (data) => {
try {
const response = await store.product.uploadProduct(data);
if (response.status === 201) {
message.success("Success Create Product by Excel!");
} else {
message.error("Failed Create Product by Excel!");
}
return response;
} catch (e) {
setLoading(false);
message.error("Failed Create Product by Excel!");
}
};
const handleCancel = () => {
form.resetFields();
setFileList([]);
setExcel("");
setVisibleModalUpload(false);
};
const handleSubmit = async (data) => {
const request = {
fileName: excel,
supplierCode: data.supplierCode
};
const responseUploadProduct = await handleUploadProduct(request);
await store.product.getData();
setLoading(false);
setFileList([]);
setExcel("");
setVisibleModalUpload(false);
};
return (
<div className={["ppob-container"].join(" ")}>
<BreadcumbComponent data={routeData} />
<BreadcumbComponent data={routeData}/>
<Card>
<Row style={{ marginBottom: 20 }}>
<div>
<Row style={{marginBottom: 20}}>
<Col span={12}>
<Button
onClick={() => {
store.product.visibleModalFilterProduct = true;
}}
>
<FilterOutlined />
<FilterOutlined/>
Filter
</Button>
</Col>
@ -76,46 +174,114 @@ export const Product = observer(() => {
textAlign: "right",
}}
>
<Search
{/* <Search
placeholder="input search text"
style={{
width: store.ui.mediaQuery.isMobile ? 160 : 200,
marginRight: store.ui.mediaQuery.isMobile ? 0 : 10,
marginBottom: store.ui.mediaQuery.isMobile ? 10 : 0,
}}
/>
{store.authentication.userData.role === "Admin" && (
<div
/> */}
{store.authentication.userData.role == "Admin" && <div
style={{
display: store.ui.mediaQuery.isMobile ? "" : "flex",
justifyContent: "flex-end",
textAlign: "right",
}}
>
<Upload>
<Button
disabled={store.product.uploadBtnProduct}
disabled={visibleModalUpload}
style={{
marginRight: store.ui.mediaQuery.isMobile ? 0 : 10,
marginBottom: store.ui.mediaQuery.isMobile ? 10 : 10,
}}
icon={<UploadOutlined />}
icon={<PlusOutlined/>}
onClick={() => setVisibleModalUpload(true)}
>
Upload Product
Tambah Produk
</Button>
</Upload>
<Button
onClick={() => (store.product.visibleModalProduct = true)}
>
<PlusSquareOutlined /> New
</Button>
</div>
)}
</div>}
</div>
</Col>
</Row>
<ProductComponent />
</div>
<ProductComponent/>
</Card>
<Modal
visible={visibleModalUpload}
title={"Upload Excel Product"}
okText={"Create"}
cancelText="Cancel"
onCancel={() => {
form.resetFields();
handleCancel();
}}
onOk={() => {
form
.validateFields()
.then((values) => {
console.log(values, "isi form");
handleSubmit(values);
form.resetFields();
})
.catch((info) => {
console.error("Validate Failed:", info);
});
}}
>
<Form form={form} layout="vertical">
<Form.Item
name="fileName"
label="Upload Excel Product"
rules={[{required: true, message: "Please Upload Excel Product!"}]}
>
<Upload
fileList={fileList}
onChange={handleChange}
beforeUpload={(file) => beforeUpload(file)}
customRequest={(args) => uploadHandler(args)}
onRemove={(file) => {
setLoading(false);
setFileList([]);
setExcel("");
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "center",
}}
>
<Button
disabled={loading}
style={{
marginRight: store.ui.mediaQuery.isMobile ? 0 : 10,
}}
icon={<UploadOutlined/>}
>
Upload Product
</Button>
</div>
</Upload>
</Form.Item>
<Form.Item
name="supplierCode"
label="Supplier Code"
rules={[{required: true, message: "Please input Supplier Code!"}]}
>
<Select>
{store.supplier.data.map(data => (
<Option key={data.id} value={data.code}>
{data.name}
</Option>
))}
</Select>
</Form.Item>
</Form>
</Modal>
</div>
);
});

View File

@ -1,17 +1,18 @@
import React, {useContext, useEffect} from "react";
import {Button, Card, Col, Row, Table, Typography} from "antd";
import {Card, Col, Row, Table, Typography} from "antd";
import {BreadcumbComponent} from "../../component/BreadcumbComponent";
import {LINKS} from "../../routes/app";
import {useStore} from "../../utils/useStore";
import {observer} from "mobx-react-lite";
import {FilterOutlined} from "@ant-design/icons";
import {format, parseISO} from "date-fns";
import {ModalLoaderContext} from "../../utils/modal";
import {useParams} from "react-router-dom";
const {Title, Text} = Typography;
export const ProductDetail = observer(() => {
const store = useStore();
const {id} = useParams();
const modalLoader = useContext(ModalLoaderContext);
const routeData = [
@ -21,11 +22,11 @@ export const ProductDetail = observer(() => {
},
{
route: LINKS.PRODUCT,
name: <span style={{fontWeight: "bold"}}>Product</span>,
name: <span style={{ fontWeight: "bold" }}>Produk</span>,
},
{
route: LINKS.PRODUCT_DETAIL,
name: <span style={{fontWeight: 'bold'}}>Product Detail</span>,
name: <span style={{ fontWeight: "bold" }}>Detail Produk</span>,
},
];
@ -33,89 +34,105 @@ export const ProductDetail = observer(() => {
(async () => {
modalLoader.setLoading(true);
await Promise.allSettled([
store.authentication.getProfile(),
store.transaction.getDataHistoryTransaction(),
store.product.getPriceHistoryByProduct(id),
store.product.getDetailProduct(id),
]);
modalLoader.setLoading(false);
})()
})();
}, []);
const columns = [
{
title: 'Markup Price',
dataIndex: 'mark_up_price',
key: 'mark_up_price',
width: '20%',
title: "Markup Price",
dataIndex: "mark_up_price",
key: "mark_up_price",
render: (text) =>
new Intl.NumberFormat("id-ID", {
style: "currency",
currency: "IDR",
}).format(text),
},
{
title: 'Name',
dataIndex: 'name',
key: 'name',
width: '50%',
title: "Price",
dataIndex: "price",
key: "price",
render: (text) =>
new Intl.NumberFormat("id-ID", {
style: "currency",
currency: "IDR",
}).format(text),
},
{
title: 'Transaction Date',
dataIndex: 'created_at',
key: 'created_at',
render: (text, record) => {
title: "Tanggal Berlaku",
dataIndex: "startDate",
key: "startDate",
render: (text) => {
return (
<Text>{format(parseISO(record.created_at), 'dd MMMM yyyy HH:mm')}</Text>
)
<Text>{text ? format(parseISO(text), "dd MMMM yyyy") : "-"}</Text>
);
},
},
]
{
title: "Tanggal Berakhir",
dataIndex: "endDate",
key: "endDate",
render: (text) => {
return (
<Text>{text ? format(parseISO(text), "dd MMMM yyyy") : "Sampai Sekarang"}</Text>
);
},
},
];
const styleSaldoTitle = store.ui.mediaQuery.isDesktop ? {
const styleSaldoTitle = store.ui.mediaQuery.isDesktop
? {
display: "flex",
justifyContent: "center"
} : {fontSize: "0.75rem"};
const styleSaldoContent = store.ui.mediaQuery.isDesktop ? {
fontSize: '1.25rem',
justifyContent: "center",
}
: { fontSize: "0.75rem" };
const styleSaldoContent = store.ui.mediaQuery.isDesktop
? {
fontSize: "1.25rem",
display: "flex",
justifyContent: "center"
} : null;
justifyContent: "center",
}
: null;
return (
<div className={["ppob-container"].join(" ")}>
<BreadcumbComponent data={routeData}/>
<BreadcumbComponent data={routeData} />
<Card>
<Title strong>Product Detail</Title>
<Row style={{marginBottom: 20}}>
<Row style={{ marginBottom: 20 }}>
<Col lg={12} xs={24}>
<Row>
<Col span={12}>
<Text strong>Kode</Text>
</Col>
<Col span={12}>
<Text>{store.authentication.profileData?.userDetail?.name}</Text>
<Text>{store.product?.dataDetailProduct?.code}</Text>
</Col>
<Col span={12}>
<Text strong>Produk</Text>
<Text strong>Nama Produk</Text>
</Col>
<Col span={10}>
<Text>{store.product?.dataDetailProduct?.name}</Text>
</Col>
<Col span={12}>
<Text>{store.authentication.profileData?.userDetail?.phone_number}</Text>
<Text strong>Supplier</Text>
</Col>
<Col span={12}>
<Text strong>Harga Beli</Text>
</Col>
<Col span={12}>
<Text>{store.authentication.profileData?.username}</Text>
</Col>
<Col span={12}>
<Text strong>Harga Jual</Text>
</Col>
<Col span={12}>
<Text>{store.authentication.profileData.roles?.name}</Text>
<Text>{store.product?.dataDetailProduct?.supplier?.name}</Text>
</Col>
<Col span={12}>
<Text strong>Status</Text>
</Col>
<Col span={12}>
<Text>{store.authentication.profileData.superior?.username}</Text>
<Text>{store.product?.dataDetailProduct?.status}</Text>
</Col>
</Row>
</Col>
<Col lg={12} xs={24}>
{/* <Col lg={12} xs={24}>
<Row justify={"center"}>
<Col lg={24} xs={12}>
<Title strong level={3} style={styleSaldoTitle}>Saldo</Title>
@ -124,29 +141,46 @@ export const ProductDetail = observer(() => {
<Text style={styleSaldoContent}>{store.authentication.profileData?.wallet}</Text>
</Col>
</Row>
</Col>
</Col> */}
</Row>
<Row>
<Col span={24}>
<div>
<Title strong level={3}>History User Transaction</Title>
<Title strong level={3}>
Product Price History
</Title>
<Button style={{marginBottom: '1rem'}} onClick={() => {
{/* <Button style={{marginBottom: '1rem'}} onClick={() => {
console.log('clicked filter')
}}>
<FilterOutlined/>
Filter
</Button>
</Button> */}
<Table
columns={columns}
dataSource={store.transaction.dataHistoryTransaction}
dataSource={store.product.dataPriceHistory}
bordered
pagination={{
pageSize: store.product.pageSizePriceHistory,
total: store.product.totalDataPriceHistory,
current: store.product.pagePriceHistory + 1,
showSizeChanger: true,
simple: false,
}}
onChange={async (page) => {
let pageNumber = page.current;
store.product.pageSizePriceHistory = page.pageSize;
store.product.pagePriceHistory = pageNumber - 1;
modalLoader.setLoading(true);
await store.product.getPriceHistoryByProduct(id);
modalLoader.setLoading(false);
}}
/>
</div>
</Col>
</Row>
<div/>
<div />
</Card>
</div>
)
);
});

View File

@ -45,7 +45,7 @@ export const Subcategory = observer(() => {
},
{
route: LINKS.SUBCATEGORY,
name: <span style={{fontWeight: "bold"}}>Sub Category</span>,
name: <span style={{fontWeight: "bold"}}>Sub Kategori</span>,
},
];
@ -54,21 +54,21 @@ export const Subcategory = observer(() => {
<BreadcumbComponent data={routeData}/>
<Card>
<Row style={{marginBottom: 20}}>
<Col span={12}>
{/* <Button>
{/* <Col span={12}>
<Button>
<FilterOutlined />
Filter
</Button> */}
</Col>
<Col span={12} style={{textAlign: "right"}}>
<Search
</Button>
</Col> */}
<Col span={24} style={{textAlign: "right"}}>
{/* <Search
placeholder="input search text"
style={{
width: store.ui.mediaQuery.isMobile ? 160 : 200,
marginRight: store.ui.mediaQuery.isMobile ? 0 : 10,
marginBottom: store.ui.mediaQuery.isMobile ? 10 : 0,
}}
/>
/> */}
<Button
onClick={() => (store.subcategory.visibleModalSubcategory = true)}
>

View File

@ -21,7 +21,7 @@ export const Profile = observer(() => {
},
{
route: LINKS.PROFILE,
name: <span style={{fontWeight: 'bold'}}>Profile</span>,
name: <span style={{fontWeight: 'bold'}}>Profil</span>,
},
];
@ -60,7 +60,7 @@ export const Profile = observer(() => {
key: 'created_at',
render: (text, record) => {
return (
<Text>{format(parseISO(record.created_at), 'dd MMMM yyyy HH:mm')}</Text>
<Text>{format(parseISO(record.created_at), 'mm:HH dd MM YYYY')}</Text>
)
},
},

View File

@ -1,12 +1,12 @@
import React, {useContext, useEffect} from "react";
import {useStore} from "../../utils/useStore";
import {Button, Card, Col, Input, message, Modal, Row, Select} from "antd";
import {observer} from "mobx-react-lite";
import {MoneyCollectOutlined} from "@ant-design/icons";
import {ModalLoaderContext} from "../../utils/modal";
import React, { useContext, useEffect } from "react";
import { useStore } from "../../utils/useStore";
import { Button, Card, Col, Input, message, Modal, Row, Select } from "antd";
import { observer } from "mobx-react-lite";
import { MoneyCollectOutlined } from "@ant-design/icons";
import { ModalLoaderContext } from "../../utils/modal";
const {Search} = Input;
const {Option} = Select;
const { Search } = Input;
const { Option } = Select;
export const Product = observer(() => {
const store = useStore();
@ -18,8 +18,8 @@ export const Product = observer(() => {
modalLoader.setLoading(true);
await Promise.allSettled([
store.transaction.getDataSubCategories(),
store.transaction.getDataCategories()
])
store.transaction.getDataCategories(),
]);
modalLoader.setLoading(false);
} catch (e) {
modalLoader.setLoading(false);
@ -44,11 +44,13 @@ export const Product = observer(() => {
const handleBuyProduct = async (data) => {
modalLoader.setLoading(true);
try {
const response = await store.transaction.buyProduct({productCode: data});
const response = await store.transaction.buyProduct({
productCode: data,
});
if (response.status === 201) {
message.success("Success Buy Product");
message.success("Berhasil Beli Produk");
} else {
message.error("Failed Buy Product", 3);
message.error("Gagal Beli Produk", 3);
}
} catch (e) {
if (e.response?.body?.message) {
@ -56,7 +58,7 @@ export const Product = observer(() => {
return;
}
console.log(e, "apa errornya");
message.error("Failed Buy Product");
message.error("Gagal Beli Product");
}
modalLoader.setLoading(false);
};
@ -64,7 +66,9 @@ export const Product = observer(() => {
return (
<div>
<Row>
<span style={{fontWeight: "bold", marginBottom: "10px"}}>Sub Category</span>
<span style={{ fontWeight: "bold", marginBottom: "10px" }}>
Sub Category
</span>
</Row>
<Row>
<Col span={24}>
@ -72,7 +76,7 @@ export const Product = observer(() => {
placeholder={"Select Sub Category"}
allowClear={true}
onChange={(val) => handleChangeSubcategory(val)}
style={{marginBottom: "10px", width: "100%"}}
style={{ marginBottom: "10px", width: "100%" }}
value={store.transaction.filterSubCategory}
>
{store.transaction.dataSubCategories.map((item, index) => (
@ -83,18 +87,18 @@ export const Product = observer(() => {
</Select>
</Col>
</Row>
<Row justify={"center"} align={"center"} style={{marginBottom: "1rem"}}>
<Row justify={"center"} align={"center"} style={{ marginBottom: "1rem" }}>
<Col
span={12}
style={{fontWeight: "bold", display: "flex", alignItems: "center"}}
style={{ fontWeight: "bold", display: "flex", alignItems: "center" }}
>
Produk & Nominal
</Col>
<Col span={12} style={{textAlign: "right"}}>
<Search
<Col span={12} style={{ textAlign: "right" }}>
{/* <Search
placeholder="input search text"
style={{width: 200, marginRight: 10}}
/>
style={{ width: 200, marginRight: 10 }}
/> */}
</Col>
</Row>
{store.transaction.data.length != 0 && (
@ -105,23 +109,30 @@ export const Product = observer(() => {
onClick={() => {
Modal.confirm({
title: `Are you sure buy ${item.product_name}?`,
icon: <MoneyCollectOutlined/>,
icon: <MoneyCollectOutlined />,
okText: "Confirm",
cancelText: "Cancel",
okType: "primary",
onOk() {
handleBuyProduct(item.product_code)
handleBuyProduct(item.product_code);
},
onCancel() {
console.log("Cancel");
},
});
}}
style={{cursor: "pointer"}}
hoverable
style={{
cursor: "pointer",
marginLeft: 10,
borderColor: "salmon",
height: 100,
marginBottom: 10,
}}
>
<span style={{color: "black"}}>{item.product_name}</span>
<br/>
<span style={{color: "grey", fontSize: 10}}>
<span style={{ color: "black" }}>{item.product_name}</span>
<br />
<span style={{ color: "grey", fontSize: 10 }}>
{new Intl.NumberFormat("id-ID", {
style: "currency",
currency: "IDR",
@ -132,13 +143,13 @@ export const Product = observer(() => {
))}
</Row>
)}
{store.transaction.data.length !== 0 && (
{/* {store.transaction.data.length !== 0 && (
<Col style={{textAlign: "right", marginTop: "1em"}}>
<Button style={{backgroundColor: "#2D9CDB", color: "white"}}>
Beli Sekarang
</Button>
</Col>
)}
)} */}
</div>
);
});

View File

@ -50,7 +50,7 @@ export const Transaction = observer(() => {
},
{
route: LINKS.TRANSACTION,
name: <span style={{fontWeight: 'bold'}}>Transaction</span>,
name: <span style={{fontWeight: 'bold'}}>Transaksi</span>,
},
];

View File

@ -29,8 +29,8 @@ export const LINKS = {
PAYBACK: "/app/payback",
PAYBACK_CREATED: "/app/payback-created",
SUBCATEGORY: "/app/subcategory",
USER_DETAIL: "/app/user-detail",
PRODUCT_DETAIL: "/app/product-detail",
USER_DETAIL: "/app/user-detail/:id",
PRODUCT_DETAIL: "/app/product-detail/:id",
};
export const AppRoute = () => {

View File

@ -63,5 +63,6 @@ export class Authentication {
TokenUtil.clearAccessToken();
TokenUtil.persistToken();
this.isLoggedIn = false;
window.location.reload();
}
}

View File

@ -5,7 +5,9 @@ export class Membership {
page = 0;
pageSize = 10
data = [];
total_data = 0
totalData = 0;
dataDetail = {};
constructor(ctx) {
this.ctx = ctx;
@ -18,12 +20,23 @@ export class Membership {
this.data = response.body.data.map((item, idx) => {
item.key = idx;
item.name = item?.user_detail?.name;
item.phone_number = item?.user_detail?.phone_number;item.roleId = item?.roles.id;
item.phone_number = item?.user_detail?.phone_number;
item.roleId = item?.roles.id;
item.roleName = item?.roles.name;
return item
}) ?? []
this.total_data = response?.body?.count ?? 0
this.totalData = response?.body?.count ?? 0
} catch (e) {
console.error(e);
}
}
async getDetail(id) {
try {
const response = await http.get(`/users/`+id);
console.log(response,'Data Detail')
this.dataDetail = response.body.data
} catch (e) {
console.error(e);
}
@ -35,12 +48,13 @@ export class Membership {
this.data = response.body.data.map((item, idx) => {
item.key = idx;
item.name = item?.user_detail?.name;
item.phone_number = item?.user_detail?.phone_number;item.roleId = item?.roles.id;
item.phone_number = item?.user_detail?.phone_number;
item.roleId = item?.roles.id;
item.roleName = item?.roles?.name;
return item
}) ?? []
this.total_data = response?.body?.count ?? 0
this.totalData = response?.body?.count ?? 0
} catch (e) {
console.error(e);
}
@ -64,6 +78,15 @@ export class Membership {
}
}
async changePassword(id, data) {
try {
const response = await http.put('/users/change-password/' + id).send(data);
return response;
} catch (e) {
console.error(e);
}
}
async delete(id) {
try {
const response = await http.del('/users/' + id);

View File

@ -93,4 +93,13 @@ export class Payback {
console.error(e);
}
}
async uploadImages(data) {
try {
const response = await http.upload(data);
return response;
} catch (e) {
console.error(e);
}
}
}

View File

@ -13,7 +13,7 @@ export class Product {
uploadBtnProduct = false;
pageCategories = 0;
pageSizeCategories = 10
pageSizeCategories = 100;
dataCategories = [];
total_dataCategories = 0;
@ -23,6 +23,13 @@ export class Product {
total_dataSubCategories = 0;
filterCategory = null;
dataPriceHistory = [];
totalDataPriceHistory = 0;
pagePriceHistory = 0;
pageSizePriceHistory = 10
dataDetailProduct = {};
constructor(ctx) {
this.ctx = ctx;
makeAutoObservable(this);
@ -31,7 +38,7 @@ export class Product {
async getData() {
try {
const response = await http.get(`/product/all?supplier=${this.filterSupplier}&sub-category=${this.filterSubCategory}&page=${this.page}&pageSize=${this.pageSize}`);
//console.log(response)
console.log(response)
this.data = response.body.data.map((item, idx) => {
item.key = idx;
return item
@ -68,6 +75,25 @@ export class Product {
}
}
async getPriceHistoryByProduct(id) {
try {
const response = await http.get(`/product/price-history/${id}?page=${this.pagePriceHistory}&pageSize${this.pageSizePriceHistory}`);
this.dataPriceHistory = response.body.data
this.totalDataPriceHistory = response?.body?.count ?? 0
} catch (e) {
console.error(e);
}
}
async getDetailProduct(id) {
try {
const response = await http.get(`/product/${id}`);
this.dataDetailProduct = response.body.data
} catch (e) {
console.error(e);
}
}
async create(data) {
try {
const response = await http.post('/product').send(data);
@ -107,6 +133,24 @@ export class Product {
console.error(e);
}
}
async uploadExcel(data) {
try {
const response = await http.upload(data);
return response;
} catch (e) {
console.error(e);
}
}
async uploadProduct(data) {
try {
const response = await http.post('/product/upload-product').send(data);
return response;
} catch (e) {
console.error(e);
}
}
}

View File

@ -22,12 +22,13 @@ export class Transaction {
filterSubCategory = null;
pageHistoryTransaction = 0;
pageHistoryTopUp = 0;
pageSizeHistoryTransaction = 10
dataHistoryTransaction = [];
total_dataHistoryTransaction = 0;
dataHistoryTopUp=[];
pageHistoryTopUp = 0;
pageSizeHistoryTopUp = 10;
dataHistoryTopUp = [];
total_dataHistoryTopUp = 0;
constructor(ctx) {
@ -58,7 +59,6 @@ export class Transaction {
async getDataCategories() {
try {
const response = await http.get(`/product/categories?page=${this.pageCategories}&pageSize=${this.pageSizeCategories}`);
this.dataCategories = response.body.data ?? []
this.total_dataCategories = response?.body?.count ?? 0
if (this.dataCategories.length > 0) {
@ -72,7 +72,6 @@ export class Transaction {
async getDataHistoryTransaction() {
try {
const response = await http.get(`/transaction/history?page=${this.pageHistoryTransaction}&pageSize=${this.pageSizeHistoryTransaction}`);
this.dataHistoryTransaction = response.body.data ?? []
this.total_dataHistoryTransaction = response?.body?.count ?? 0
} catch (e) {
@ -82,9 +81,7 @@ export class Transaction {
async getDataHistoryTopUp(id) {
try {
console.log("Top up")
const response = await http.get(`/transaction/history-deposit?page=${this.pageHistoryTopUp}&user-destination=${id}`);
const response = await http.get(`/transaction/history-deposit?page=${this.pageHistoryTopUp}&pageSize=${this.pageSizeHistoryTopUp}&user-destination=${id}`);
this.dataHistoryTopUp = response.body.data ?? []
this.total_dataHistoryTopUp = response?.body?.count ?? 0
} catch (e) {