diff --git a/src/component/ProductComponent.js b/src/component/ProductComponent.js index 1ddb46a..059b695 100644 --- a/src/component/ProductComponent.js +++ b/src/component/ProductComponent.js @@ -1,4 +1,4 @@ -import React, { useContext, useState } from "react"; +import React, {useContext, useState} from "react"; import { Button, Col, @@ -15,19 +15,19 @@ import { Tag, Typography, } 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 {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"; -const { Title, Text } = Typography; +const {Title, Text} = Typography; export const ProductComponent = observer((props) => { const store = useStore(); const [form] = Form.useForm(); - const { Option } = Select; + const {Option} = Select; const history = useHistory(); const [idData, setIdData] = useState(""); const [filterSupplier, setFilterSupplier] = useState([]); @@ -107,17 +107,12 @@ export const ProductComponent = observer((props) => { key: "action", render: (text, record) => ( + onClick={async () => { + history.push(LINKS.PRODUCT_DETAIL.replace(":id", record.product_id)); + }} + > + Detail + ), }, ]; diff --git a/src/pages/Membership/DetailUser.js b/src/pages/Membership/DetailUser.js index c0afcee..1301340 100644 --- a/src/pages/Membership/DetailUser.js +++ b/src/pages/Membership/DetailUser.js @@ -1,5 +1,5 @@ import React, {useContext, useEffect, useState} from "react"; -import {Button, Card, Col, message, Row, Space, Table, Tag, Typography,} from "antd"; +import {Button, Card, Col, message, Row, Space, Table, Typography,} from "antd"; import {BreadcumbComponent} from "../../component/BreadcumbComponent"; import {LINKS} from "../../routes/app"; import {useStore} from "../../utils/useStore"; @@ -104,6 +104,11 @@ export const DetailUser = observer(() => { title: "Amount", dataIndex: "amount", key: "amount", + render: (text) => + new Intl.NumberFormat("id-ID", { + style: "currency", + currency: "IDR", + }).format(text), }, { title: "Transaction Date", @@ -112,24 +117,11 @@ export const DetailUser = observer(() => { render: (text, record) => { return ( - {format(parseISO(record.transaction_date), "dd MMMM yyyy ")} + {format(parseISO(record.transaction_date), "dd MMMM yyyy")} ); }, }, - { - title: "Status", - dataIndex: "isActive", - key: "isActive", - render: (text, record) => ( - - {store.membership.dataDetail.isActive === true ? " ACTIVE" : "INACTIVE"} - - ), - }, ]; const routeData = [ @@ -142,8 +134,8 @@ export const DetailUser = observer(() => { name: Keanggotaan, }, { - route: LINKS.USER_DETAIL, - name: Detail Anggota, + route: LINKS.USER_DETAIL.replace(":id", id), + name: Detail User, }, ]; @@ -194,56 +186,50 @@ export const DetailUser = observer(() => { - Action User Detail - Action User Detail} + {store.authentication.userData.role === "Admin" && - {store.authentication.userData.role === "Admin" && - - } - {store.authentication.userData.role === "Admin" && - - } - {store.authentication.userData.role === "Admin" && - - } - + + + + } diff --git a/src/pages/Product/Product.js b/src/pages/Product/Product.js index 3f87bcd..7cdd86e 100644 --- a/src/pages/Product/Product.js +++ b/src/pages/Product/Product.js @@ -1,6 +1,6 @@ import React, {useContext, useEffect, useState} from "react"; -import {Button, Card, Col, Input, message, Row, Upload} from "antd"; -import {FilterOutlined, LoadingOutlined, UploadOutlined,} from "@ant-design/icons"; +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"; @@ -9,15 +9,22 @@ import {LINKS} from "../../routes/app"; import {ModalLoaderContext} from "../../utils/modal"; 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(), @@ -37,6 +44,10 @@ export const Product = observer(() => { }; init(); + + return () => { + store.supplier.pageSize = 10; + }; }, []); const routeData = [ @@ -73,16 +84,21 @@ export const Product = observer(() => { const uploadHandler = async (args) => { const file = args.file; try { - const responseUpload = await store.product.uploadExcel(file); + const response = await store.product.uploadExcel(file); - if (responseUpload.status === 201) { + if (response.status === 201) { message.success("Success upload excel!"); } else { message.error("Failed upload excel!"); } - setLoading(false); - const responseUploadProduct = await handleUploadProduct(responseUpload); + setFileList([{ + uid: '-1', + name: response.body.filename, + status: 'done', + url: '', + }]); + setExcel(response.body.filename); } catch (e) { setLoading(false); message.error("Failed upload excel!"); @@ -99,33 +115,45 @@ export const Product = observer(() => { const handleUploadProduct = async (data) => { try { - const response = await store.product.uploadProduct({fileName: data.body.filename}); + 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!"); } - setLoading(false); - await store.product.getData(); return response; } catch (e) { setLoading(false); message.error("Failed Create Product by Excel!"); } - } + }; - const loadingState = ( -
- {loading ? : null} -
- ); + 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 (
- {store.authentication.userData.role !== "Admin" && (
@@ -155,42 +183,105 @@ export const Product = observer(() => { }} /> */} -
- beforeUpload(file)} - customRequest={(args) => uploadHandler(args)} - onRemove={(file) => { - setLoading(false); + - - {loadingState} -
+ Tambah Produk + +
}
- -
- - )} - - - + + + + + + + { + form.resetFields(); + handleCancel(); + }} + onOk={() => { + form + .validateFields() + .then((values) => { + console.log(values, "isi form"); + handleSubmit(values); + form.resetFields(); + }) + .catch((info) => { + console.error("Validate Failed:", info); + }); + }} + > +
+ + beforeUpload(file)} + customRequest={(args) => uploadHandler(args)} + onRemove={(file) => { + setLoading(false); + setFileList([]); + setExcel(""); + }} + > +
+ +
+
+
+ + + +
+
+ ); }); diff --git a/src/pages/Product/ProductDetail.js b/src/pages/Product/ProductDetail.js index cbe2111..e30aa91 100644 --- a/src/pages/Product/ProductDetail.js +++ b/src/pages/Product/ProductDetail.js @@ -1,19 +1,18 @@ -import React, { useContext, useEffect } from "react"; -import { Button, 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"; +import React, {useContext, useEffect} from "react"; +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 {format, parseISO} from "date-fns"; +import {ModalLoaderContext} from "../../utils/modal"; +import {useParams} from "react-router-dom"; -const { Title, Text } = Typography; +const {Title, Text} = Typography; export const ProductDetail = observer(() => { const store = useStore(); - const { id } = useParams(); + const {id} = useParams(); const modalLoader = useContext(ModalLoaderContext); const routeData = [ @@ -26,8 +25,8 @@ export const ProductDetail = observer(() => { name: Produk, }, { - route: LINKS.PRODUCT_DETAIL, - name: Detail Produk, + route: LINKS.PRODUCT_DETAIL.replace(':id', `${id}`), + name: Detail Produk, }, ]; @@ -35,21 +34,18 @@ export const ProductDetail = observer(() => { (async () => { modalLoader.setLoading(true); await Promise.allSettled([ - //store.authentication.getProfile(), - store.product.getDetail(id), + store.product.getPriceHistoryByProduct(id), store.product.getDetailProduct(id), ]); modalLoader.setLoading(false); })(); }, []); - //console.log(id) const columns = [ { title: "Markup Price", dataIndex: "mark_up_price", key: "mark_up_price", - width: "20%", render: (text) => new Intl.NumberFormat("id-ID", { style: "currency", @@ -60,7 +56,6 @@ export const ProductDetail = observer(() => { title: "Price", dataIndex: "price", key: "price", - width: "50%", render: (text) => new Intl.NumberFormat("id-ID", { style: "currency", @@ -68,12 +63,22 @@ export const ProductDetail = observer(() => { }).format(text), }, { - title: "Transaction Date", + title: "Tanggal Berlaku", dataIndex: "startDate", key: "startDate", - render: (text, record) => { + render: (text) => { return ( - {format(parseISO(record.startDate), "dd MMMM yyyy")} + {text ? format(parseISO(text), "dd MMMM yyyy") : "-"} + ); + }, + }, + { + title: "Tanggal Berakhir", + dataIndex: "endDate", + key: "endDate", + render: (text) => { + return ( + {text ? format(parseISO(text), "dd MMMM yyyy") : "Sampai Sekarang"} ); }, }, @@ -105,47 +110,25 @@ export const ProductDetail = observer(() => { Kode - {store.product.dataDetailProduct.code} + {store.product?.dataDetailProduct?.code} Nama Produk - {store.product.dataDetailProduct.name} - - - Harga Beli - - - - {new Intl.NumberFormat("id-ID", { - style: "currency", - currency: "IDR", - }).format(store.product.dataDetailProduct.basePrice)} - - - - Harga Jual - - - - {new Intl.NumberFormat("id-ID", { - style: "currency", - currency: "IDR", - }).format(store.product.dataDetailProduct.price)} - + {store.product?.dataDetailProduct?.name} Supplier - {store.product.dataDetailProduct.supplier.name} + {store.product?.dataDetailProduct?.supplier?.name} Status - {store.product.dataDetailProduct.status} + {store.product?.dataDetailProduct?.status} @@ -174,9 +157,24 @@ export const ProductDetail = observer(() => { Filter */} { + 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); + }} /> diff --git a/src/pages/Profile/Profile.js b/src/pages/Profile/Profile.js index def501f..c346341 100644 --- a/src/pages/Profile/Profile.js +++ b/src/pages/Profile/Profile.js @@ -60,7 +60,7 @@ export const Profile = observer(() => { key: 'created_at', render: (text, record) => { return ( - {format(parseISO(record.created_at), 'mm:HH dd MM YYYY')} + {format(parseISO(record.created_at), 'mm:HH dd-MM-yyyy')} ) }, }, diff --git a/src/pages/Transaction/Product.js b/src/pages/Transaction/Product.js index 88a4cb6..f8dbe01 100644 --- a/src/pages/Transaction/Product.js +++ b/src/pages/Transaction/Product.js @@ -1,16 +1,17 @@ -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, useState} from "react"; +import {useStore} from "../../utils/useStore"; +import {Card, Col, Form, Input, message, Modal, Row, Select} from "antd"; +import {observer} from "mobx-react-lite"; +import {ModalLoaderContext} from "../../utils/modal"; -const { Search } = Input; -const { Option } = Select; +const {Search} = Input; +const {Option} = Select; export const Product = observer(() => { const store = useStore(); const modalLoader = useContext(ModalLoaderContext); + const [form] = Form.useForm(); + const [visibleModalBuy, setVisibleModalBuy] = useState(false); useEffect(() => { const init = async () => { @@ -41,11 +42,12 @@ export const Product = observer(() => { modalLoader.setLoading(false); }; - const handleBuyProduct = async (data) => { + const handleBuyProduct = async (data, productCode) => { modalLoader.setLoading(true); try { const response = await store.transaction.buyProduct({ - productCode: data, + ...data, + productCode: productCode, }); if (response.status === 201) { message.success(response?.body?.message || "Berhasil Beli Produk"); @@ -60,38 +62,44 @@ export const Product = observer(() => { console.log(e, "apa errornya"); message.error("Gagal Beli Product"); } + setVisibleModalBuy(false); modalLoader.setLoading(false); }; + const handleCancel = () => { + form.resetFields(); + setVisibleModalBuy(false); + }; + return ( -
- - +
+ + Sub Category - - -
- handleChangeSubcategory(val)} + style={{marginBottom: "10px", width: "100%"}} + value={store.transaction.filterSubCategory} + > + {store.transaction.dataSubCategories.map((item, index) => ( + + ))} + + + + + - {store.transaction.dataSubCategories.map((item, index) => ( - - ))} - - - - - Produk & Nominal @@ -107,19 +115,7 @@ export const Product = observer(() => { { - Modal.confirm({ - title: `Are you sure buy ${item.product_name}?`, - icon: , - okText: "Confirm", - cancelText: "Cancel", - okType: "primary", - onOk() { - handleBuyProduct(item.product_code); - }, - onCancel() { - console.log("Cancel"); - }, - }); + setVisibleModalBuy(true) }} hoverable style={{ @@ -130,26 +126,52 @@ export const Product = observer(() => { marginBottom: 10, }} > - {item.product_name} -
- + {item.product_name} +
+ {new Intl.NumberFormat("id-ID", { style: "currency", currency: "IDR", }).format(item?.price)}
+ + { + form.resetFields(); + handleCancel(); + }} + onOk={() => { + form + .validateFields() + .then((values) => { + console.log(values, "isi form"); + handleBuyProduct(values, item.product_code); + form.resetFields(); + }) + .catch((info) => { + console.error("Validate Failed:", info); + }); + }} + > +
+ + + + +
))} )} - {/* {store.transaction.data.length !== 0 && ( - - - - )} */} ); }); diff --git a/src/store/product.js b/src/store/product.js index 65b51f2..5697d10 100644 --- a/src/store/product.js +++ b/src/store/product.js @@ -13,7 +13,7 @@ export class Product { uploadBtnProduct = false; pageCategories = 0; - pageSizeCategories = 10 + pageSizeCategories = 100; dataCategories = []; total_dataCategories = 0; @@ -22,11 +22,13 @@ export class Product { dataSubCategories = []; total_dataSubCategories = 0; filterCategory = null; - dataDetail=[] - dataDetailProduct=[] - pageGetDetail=0 - supplier=null + dataPriceHistory = []; + totalDataPriceHistory = 0; + pagePriceHistory = 0; + pageSizePriceHistory = 10 + + dataDetailProduct = {}; constructor(ctx) { this.ctx = ctx; @@ -72,22 +74,21 @@ export class Product { console.error(e); } } - async getDetail(id) { + + async getPriceHistoryByProduct(id) { try { - const response = await http.get(`/product/price-history/${id}?page=${this.pageGetDetail}&supplier=${this.supplier}`); - //console.log(response,' Detail') - this.dataDetail = response.body.data - this.total_data = response?.body?.count ?? 0 + 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}`); - //console.log(response,' Detail Product') this.dataDetailProduct = response.body.data - this.total_data = response?.body?.count ?? 0 } catch (e) { console.error(e); }