feat: initial commit
This commit is contained in:
20
src/pages/About/About.js
Normal file
20
src/pages/About/About.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import React from "react";
|
||||
import {PageHeader} from "antd";
|
||||
|
||||
export const About = () => {
|
||||
return <div>
|
||||
<PageHeader
|
||||
style={{
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
height: 40,
|
||||
backgroundColor: "transparent",
|
||||
}}
|
||||
title={"About"}
|
||||
>
|
||||
</PageHeader>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus aut recusandae velit! Consequatur corporis,
|
||||
eum fuga, harum incidunt laboriosam minus necessitatibus neque non nostrum pariatur tempore. Dignissimos impedit
|
||||
rem tempora!
|
||||
</div>
|
||||
};
|
24
src/pages/App/App.js
Normal file
24
src/pages/App/App.js
Normal file
@@ -0,0 +1,24 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {DesktopLayout} from "./DesktopLayout";
|
||||
import {useMediaQuery} from 'react-responsive';
|
||||
import {useStore} from "../../utils/useStore";
|
||||
|
||||
|
||||
export const App = () => {
|
||||
// TODO: add mobile layout
|
||||
const store = useStore();
|
||||
const mediaQuery = {
|
||||
isDesktop: useMediaQuery({minWidth: 1024}),
|
||||
isTablet: useMediaQuery({minWidth: 768, maxWidth: 1023}),
|
||||
isMobile: useMediaQuery({maxWidth: 767}),
|
||||
isNotMobile: useMediaQuery({minWidth: 768}),
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
store.ui.setMediaQuery(mediaQuery);
|
||||
});
|
||||
// const isMobileDevice = useMediaQuery({
|
||||
// query: "(min-device-width: 480px)",
|
||||
// });
|
||||
return <DesktopLayout/>;
|
||||
};
|
151
src/pages/App/DesktopLayout.js
Normal file
151
src/pages/App/DesktopLayout.js
Normal file
@@ -0,0 +1,151 @@
|
||||
import React, {useState} from "react";
|
||||
import {Button, Layout, Menu, Popover, Typography,} from "antd";
|
||||
import {MenuList} from "./MenuList";
|
||||
import {Link} from "react-router-dom";
|
||||
import {PlusSquareOutlined, UserOutlined,} from "@ant-design/icons";
|
||||
import {AppRoute} from "../../routes/app";
|
||||
|
||||
const {Text, Paragraph} = Typography;
|
||||
const {Header, Content, Sider} = Layout;
|
||||
|
||||
export const DesktopLayout = () => {
|
||||
const [clicked, setClicked] = useState(false);
|
||||
|
||||
return (
|
||||
<Layout
|
||||
theme={"light"}
|
||||
className={"transparent"}
|
||||
hasSider={true}
|
||||
style={{
|
||||
paddingLeft: 0,
|
||||
display: "flex",
|
||||
width: "100vw",
|
||||
height: "100vh",
|
||||
}}
|
||||
>
|
||||
<Sider
|
||||
className={"transparent"}
|
||||
width={240}
|
||||
style={{
|
||||
overflowX: "hidden",
|
||||
bottom: 0,
|
||||
justifyContent: "flex-start",
|
||||
paddingTop: 20,
|
||||
paddingLeft: 20,
|
||||
position: "fixed",
|
||||
top: 0,
|
||||
zIndex: 10,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
paddingLeft: 20,
|
||||
marginBottom: 40,
|
||||
}}
|
||||
>
|
||||
<Paragraph
|
||||
style={{
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: 20,
|
||||
marginLeft: 5,
|
||||
fontWeight: 600,
|
||||
color: "#828282",
|
||||
}}
|
||||
>
|
||||
PPOB
|
||||
</Paragraph>
|
||||
<Paragraph
|
||||
style={{
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: 11,
|
||||
marginLeft: 5,
|
||||
fontWeight: 600,
|
||||
color: "#413d3e",
|
||||
}}
|
||||
>
|
||||
Admin
|
||||
</Paragraph>
|
||||
</div>
|
||||
<MenuList closeLeftDrawer={() => {
|
||||
}}/>
|
||||
</Sider>
|
||||
|
||||
<Layout
|
||||
style={{
|
||||
paddingLeft: 240,
|
||||
}}
|
||||
>
|
||||
<Header
|
||||
theme={"light"}
|
||||
style={{
|
||||
height: 54,
|
||||
paddingLeft: 0,
|
||||
paddingRight: 0,
|
||||
backgroundColor: "transparent",
|
||||
maxWidth: 1000,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "flex-end",
|
||||
}}
|
||||
>
|
||||
<Button style={{right: "94%"}}>
|
||||
<PlusSquareOutlined/>
|
||||
</Button>
|
||||
<Popover
|
||||
autoAdjustOverflow={true}
|
||||
placement="bottomRight"
|
||||
content={
|
||||
<Menu
|
||||
type={"line"}
|
||||
inlineIndent={0}
|
||||
theme="light"
|
||||
style={{
|
||||
backgroundColor: "transparent",
|
||||
borderRightWidth: 0,
|
||||
right: "30%",
|
||||
}}
|
||||
mode="inline"
|
||||
>
|
||||
<Menu.Item>
|
||||
<Link to="/app/profile">
|
||||
<span>Profile</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
onClick={() => {
|
||||
// store.authentication.logout();
|
||||
// return history.push("/login");
|
||||
}}
|
||||
>
|
||||
<span>Sign out</span>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
}
|
||||
title={
|
||||
<Text>
|
||||
info@bangun-kreatif.com
|
||||
{/*{store.userData.email}{" "}*/}
|
||||
<Paragraph style={{fontWeight: 400}} type={"secondary-dark"}>
|
||||
Administrator
|
||||
{/*{store.userData.role}*/}
|
||||
</Paragraph>
|
||||
</Text>
|
||||
}
|
||||
trigger="click"
|
||||
visible={clicked}
|
||||
onVisibleChange={() => setClicked(!clicked)}
|
||||
>
|
||||
<Button
|
||||
size={"default"}
|
||||
style={{}}
|
||||
icon={<UserOutlined style={{fontSize: "13px"}}/>}
|
||||
/>
|
||||
</Popover>
|
||||
</Header>
|
||||
<AppRoute/>
|
||||
</Layout>
|
||||
</Layout>
|
||||
);
|
||||
};
|
69
src/pages/App/MenuList.js
Normal file
69
src/pages/App/MenuList.js
Normal file
@@ -0,0 +1,69 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {Menu} from "antd";
|
||||
import {Link} from "react-router-dom";
|
||||
import {CalendarOutlined, HomeOutlined,} from "@ant-design/icons";
|
||||
import {observer} from "mobx-react-lite";
|
||||
import {useStore} from "../../utils/useStore";
|
||||
|
||||
const {SubMenu} = Menu;
|
||||
|
||||
export const MenuList = observer((props) => {
|
||||
const store = useStore();
|
||||
useEffect(() => {
|
||||
}, []);
|
||||
|
||||
const [setKeys, setSetKeys] = useState(["dashboard"]);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
defaultOpenKeys={["sub4"]}
|
||||
theme="light"
|
||||
style={{
|
||||
backgroundColor: "transparent",
|
||||
borderRightWidth: 0,
|
||||
fontWeight: 400,
|
||||
paddingLeft: 0,
|
||||
}}
|
||||
onClick={({keyPath, item}) => {
|
||||
props.closeLeftDrawer();
|
||||
}}
|
||||
mode="inline"
|
||||
selectedKeys={setKeys}
|
||||
onSelect={({setKeys, item, selectedKeys}) => setSetKeys(selectedKeys)}
|
||||
overflowedIndicator={0}
|
||||
forceSubMenuRender={true}
|
||||
>
|
||||
<Menu.Item key="home">
|
||||
<Link to={'/app/home'}>
|
||||
<HomeOutlined/>
|
||||
<span>Home</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="membership">
|
||||
<Link to={'/app/membership'}>
|
||||
<HomeOutlined/>
|
||||
<span>Membership</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="product">
|
||||
<Link to={'/app/product'}>
|
||||
<HomeOutlined/>
|
||||
<span>Product</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="product">
|
||||
<Link to={'/app/transaction'}>
|
||||
<HomeOutlined/>
|
||||
<span>Transaction</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>
|
||||
);
|
||||
});
|
25
src/pages/Home/Home.js
Normal file
25
src/pages/Home/Home.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import React from "react";
|
||||
import {Button, PageHeader} from "antd";
|
||||
import {store} from "../../utils/useStore";
|
||||
import {observer} from "mobx-react-lite";
|
||||
|
||||
export const Home = observer(() => {
|
||||
return <div>
|
||||
<PageHeader
|
||||
style={{
|
||||
padding: 0,
|
||||
margin: 0,
|
||||
height: 40,
|
||||
backgroundColor: "transparent",
|
||||
}}
|
||||
title={"Home"}
|
||||
>
|
||||
</PageHeader>
|
||||
<Button onClick={() => {
|
||||
store.ui.setTestValue();
|
||||
}}>{store.ui.testValue}</Button>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus aut recusandae velit! Consequatur corporis,
|
||||
eum fuga, harum incidunt laboriosam minus necessitatibus neque non nostrum pariatur tempore. Dignissimos impedit
|
||||
rem tempora!
|
||||
</div>
|
||||
});
|
139
src/pages/Login/Login.js
Normal file
139
src/pages/Login/Login.js
Normal file
@@ -0,0 +1,139 @@
|
||||
import React, {useState} from "react";
|
||||
import {observer} from 'mobx-react-lite';
|
||||
import {useStore} from "../../utils/useStore";
|
||||
import {Button, Card, Checkbox, Col, Form, Input, Row, Typography} from 'antd';
|
||||
import {LockOutlined, UserOutlined} from '@ant-design/icons';
|
||||
import {useHistory} from "react-router-dom";
|
||||
|
||||
export const Login = observer(() => {
|
||||
const store = useStore();
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
let history = useHistory();
|
||||
|
||||
const onFinish = values => {
|
||||
console.log('Received values of form: ', values);
|
||||
enterLoading(values).then(res => {
|
||||
console.log(res, "awasaa");
|
||||
}).catch((error) => {
|
||||
console.log({error}, "awasaa error");
|
||||
});
|
||||
};
|
||||
|
||||
const enterLoading = async (props) => {
|
||||
// store.setInitialToken("ayayay", "clap");
|
||||
return history.push("/app/page_example_1");
|
||||
};
|
||||
|
||||
return <div style={{width: '100vw', display: 'flex', justifyContent: 'center'}}>
|
||||
<Row justify={'center'}>
|
||||
<Col>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-start',
|
||||
marginTop: '5vh',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
}}>
|
||||
<div style={{display: 'flex', flexDirection: 'column', alignItems: 'stretch'}}>
|
||||
<Typography.Paragraph
|
||||
style={{
|
||||
margin: 0,
|
||||
padding: 0,
|
||||
fontSize: 20,
|
||||
marginLeft: 5,
|
||||
fontWeight: 600,
|
||||
color: "#413d3e",
|
||||
}}
|
||||
>
|
||||
Boilerplate
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
<Card
|
||||
style={{width: 320, textAlign: 'center'}}
|
||||
headStyle={{fontSize: 13, fontWeight: 200}}
|
||||
className={"shadow"}
|
||||
bordered={true}
|
||||
title={'Sign in to your account'}
|
||||
>
|
||||
<Form
|
||||
layout={'vertical'}
|
||||
name="normal_login"
|
||||
className="login-form"
|
||||
onFinish={onFinish}
|
||||
>
|
||||
<Form.Item
|
||||
label="Email"
|
||||
name="email"
|
||||
size={'large'}
|
||||
rules={[{required: false, message: 'Please input your Username!'}]}
|
||||
>
|
||||
<Input
|
||||
prefix={<UserOutlined className="site-form-item-icon"/>}
|
||||
type="text"
|
||||
placeholder="Email"/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
style={{
|
||||
marginBottom: 0,
|
||||
}}
|
||||
label="Password"
|
||||
name="password"
|
||||
size={'large'}
|
||||
rules={[{required: false, message: 'Please input your Password!'}]}
|
||||
>
|
||||
<Input.Password
|
||||
prefix={<LockOutlined className="site-form-item-icon"/>}
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
style={{
|
||||
marginTop: 0,
|
||||
marginBottom: 20,
|
||||
padding: 0
|
||||
}}
|
||||
// label="Password"
|
||||
name="forgot-password"
|
||||
size={'small'}
|
||||
rules={[{required: false, message: 'Please input your Password!'}]}
|
||||
>
|
||||
<a className="login-form-forgot" href="">
|
||||
Forgot password
|
||||
</a>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
style={{
|
||||
marginBottom: 5,
|
||||
textAlign: 'left'
|
||||
}}>
|
||||
<Form.Item name="remember" valuePropName="checked" noStyle>
|
||||
<Checkbox>Remember me</Checkbox>
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
style={{
|
||||
marginBottom: 0,
|
||||
}}>
|
||||
<Button type="primary"
|
||||
block
|
||||
loading={loading}
|
||||
htmlType="submit"
|
||||
size={'large'}
|
||||
onSubmit={enterLoading}
|
||||
className="login-form-button">
|
||||
Sign In
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Card>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
</div>;
|
||||
});
|
280
src/pages/Membership/Membership.js
Normal file
280
src/pages/Membership/Membership.js
Normal file
@@ -0,0 +1,280 @@
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {Button, Card, Col, Input, List, message, Modal, PageHeader, Row, Space, Table, Tag} from "antd";
|
||||
import {useStore} from "../../utils/useStore";
|
||||
import {observer} from "mobx-react-lite";
|
||||
import {ExclamationCircleOutlined, FilterOutlined, PlusSquareOutlined,} from "@ant-design/icons";
|
||||
import {MembershipModal} from "./MembershipModal";
|
||||
import {BreadcumbComponent} from "../../component/BreadcumbComponent";
|
||||
|
||||
const {Search} = Input;
|
||||
|
||||
export const Membership = observer(() => {
|
||||
const store = useStore();
|
||||
const [visibleModal, setVisibleModal] = useState(false)
|
||||
const [initialData, setInitialData] = useState({})
|
||||
const [confirmLoading, setConfirmLoading] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
await store.membership.getData();
|
||||
setIsLoading(false)
|
||||
} catch (e) {
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
init()
|
||||
|
||||
}, []);
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "Name",
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
},
|
||||
{
|
||||
title: "Username",
|
||||
dataIndex: "username",
|
||||
key: "username",
|
||||
},
|
||||
{
|
||||
title: "Status",
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
render: (text, record) => (
|
||||
<>
|
||||
<Tag color="#E3E8EE" style={{color: "#4F566B"}}>
|
||||
Inactive
|
||||
</Tag>
|
||||
<Tag color="processing">Active</Tag>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: "Action",
|
||||
key: "action",
|
||||
render: (text, record) => (
|
||||
<Space size="middle">
|
||||
<Button onClick={() => {
|
||||
setVisibleModal(true)
|
||||
setInitialData(record)
|
||||
}}>Edit</Button>
|
||||
<Button onClick={async () => {
|
||||
handleDelete(record.id)
|
||||
|
||||
}}
|
||||
>Delete</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const routeData = [
|
||||
{
|
||||
route: "/app/home",
|
||||
name: "Home",
|
||||
},
|
||||
{
|
||||
route: "/app/membership",
|
||||
name: <span style={{fontWeight: "bold"}}>Membership</span>,
|
||||
},
|
||||
];
|
||||
|
||||
const onSubmit = async (data) => {
|
||||
if (initialData.id) {
|
||||
setInitialData({})
|
||||
setConfirmLoading(true);
|
||||
try {
|
||||
await store.membership.update(initialData.id, data)
|
||||
message.success("Success Update Data Member")
|
||||
} catch (e) {
|
||||
message.error("Failed Update Data Member")
|
||||
}
|
||||
setConfirmLoading(false);
|
||||
setVisibleModal(false);
|
||||
} else {
|
||||
setInitialData({})
|
||||
setConfirmLoading(true);
|
||||
try {
|
||||
await store.membership.create(data)
|
||||
message.success("Success Add New Member")
|
||||
} catch (e) {
|
||||
console.log(e, "apa errornya")
|
||||
message.error("Failed Add Member")
|
||||
}
|
||||
setConfirmLoading(false);
|
||||
setVisibleModal(false);
|
||||
}
|
||||
}
|
||||
|
||||
const handleDelete = (record) => {
|
||||
Modal.confirm({
|
||||
title: 'Are you sure reject this record?',
|
||||
icon: <ExclamationCircleOutlined/>,
|
||||
okText: 'Yes',
|
||||
okType: 'primary',
|
||||
cancelText: 'Cancel',
|
||||
onOk() {
|
||||
try {
|
||||
//TODO: minta apinya ke ka ilham ya, jangan di uncomment kalo pake api reconcile, nanti beneran ke apus datanya
|
||||
// await store.membership.delete(record.id)
|
||||
message.success('Success Delete Data')
|
||||
} catch (e) {
|
||||
message.error("Failed Delete Data")
|
||||
}
|
||||
},
|
||||
onCancel() {
|
||||
console.log('Cancel');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<BreadcumbComponent data={routeData}/>
|
||||
<Card>
|
||||
{store.ui.mediaQuery.isDesktop && (
|
||||
<div>
|
||||
<Row style={{marginBottom: 20}}>
|
||||
<Col span={12}>
|
||||
<Button>
|
||||
<FilterOutlined/>
|
||||
Filter
|
||||
</Button>
|
||||
</Col>
|
||||
<Col span={12} style={{textAlign: "right"}}>
|
||||
<Search
|
||||
placeholder="input search text"
|
||||
style={{width: 200, marginRight: 10}}
|
||||
/>
|
||||
<Button onClick={() => setVisibleModal(true)}>
|
||||
<PlusSquareOutlined/> New
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Table
|
||||
style={{textAlign: "center"}}
|
||||
columns={columns}
|
||||
dataSource={store.membership.data}
|
||||
bordered
|
||||
pagination={{
|
||||
total: store.membership.total_data,
|
||||
current: store.membership.page,
|
||||
pageSize: store.membership.pageSize,
|
||||
simple: true
|
||||
}} onChange={(page) => {
|
||||
store.membership.pageSize = page.pageSize;
|
||||
store.membership.page = page.current;
|
||||
store.membership.getData();
|
||||
}} current={store.membership.page}
|
||||
loading={store.membership.pageSize}/>
|
||||
</div>
|
||||
)}
|
||||
{store.ui.mediaQuery.isMobile && (
|
||||
<div>
|
||||
<Card bordered={false} bodyStyle={{padding: "0"}} style={{borderRadius: 0, width: '50%'}}>
|
||||
<PageHeader
|
||||
className={"card-page-header"}
|
||||
style={{
|
||||
padding: "6px 8px",
|
||||
}}
|
||||
title={
|
||||
<Button
|
||||
icon={<FilterOutlined/>}
|
||||
size={"small"}
|
||||
style={{margin: 3}}
|
||||
>
|
||||
Filter
|
||||
</Button>
|
||||
}
|
||||
subTitle=""
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<List
|
||||
itemLayout="horizontal"
|
||||
position={"top"}
|
||||
dataSource={store.membership.data}
|
||||
style={{padding: 0}}
|
||||
renderItem={(item) => {
|
||||
console.log(item, "item ->");
|
||||
return (
|
||||
<div>
|
||||
<List.Item
|
||||
key={item.key}
|
||||
style={{
|
||||
backgroundColor: "#ffffff",
|
||||
paddingTop: 0,
|
||||
paddingBottom: 0,
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "50%"
|
||||
}}
|
||||
>
|
||||
<List.Item.Meta
|
||||
className={["cariparkir-container"].join(" ")}
|
||||
title={<h3 style={{marginBottom: 0, color: "#5469d4"}}>{item.name}</h3>}
|
||||
description={
|
||||
<div style={{}}>
|
||||
<p>
|
||||
<small>Username : {item.username}</small> <br/>
|
||||
</p>
|
||||
<p>
|
||||
{item.status}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
{/* <div style={{ marginRight: 16 }}>
|
||||
<Statistic
|
||||
title={
|
||||
<p
|
||||
style={{
|
||||
fontSize: 9,
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
{item.updated_at ? moment(item.updated_at).format("DD MMM YY, H:mm:ss") : "There is not top up yet"}
|
||||
</p>
|
||||
}
|
||||
prefix={"Rp"}
|
||||
precision={0}
|
||||
style={{ fontSize: 12, fontWeight: 300 }}
|
||||
valueStyle={{
|
||||
color: "#5469d4",
|
||||
fontSize: 12,
|
||||
fontWeight: 600,
|
||||
textAlign: "right",
|
||||
}}
|
||||
value={item.balances}
|
||||
/>
|
||||
|
||||
</div> */}
|
||||
</List.Item>
|
||||
{/* <Divider plain style={{ margin: 0 }} /> */}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
<MembershipModal visible={visibleModal}
|
||||
confirmLoading={confirmLoading}
|
||||
initialData={initialData}
|
||||
onCreate={async (data) => {
|
||||
onSubmit(data)
|
||||
}}
|
||||
onCancel={() => {
|
||||
setInitialData({})
|
||||
setVisibleModal(false);
|
||||
}}/>
|
||||
</div>
|
||||
);
|
||||
});
|
82
src/pages/Membership/MembershipModal.js
Normal file
82
src/pages/Membership/MembershipModal.js
Normal file
@@ -0,0 +1,82 @@
|
||||
import React from 'react';
|
||||
import {Form, Input, Modal, Select,} from 'antd';
|
||||
|
||||
export const MembershipModal = ({
|
||||
visible,
|
||||
onCreate,
|
||||
onCancel,
|
||||
initialData,
|
||||
}) => {
|
||||
const [form] = Form.useForm();
|
||||
const {Option} = Select;
|
||||
const dataStatus = ['Active', 'Inactive']
|
||||
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
title={initialData.id ? "Edit Member" : "Create a new Member"}
|
||||
okText={initialData.id ? "Edit" : "Create"}
|
||||
cancelText="Cancel"
|
||||
onCancel={() => {
|
||||
form.resetFields()
|
||||
onCancel()
|
||||
}}
|
||||
onOk={() => {
|
||||
form
|
||||
.validateFields()
|
||||
.then(values => {
|
||||
onCreate(values);
|
||||
form.resetFields()
|
||||
})
|
||||
.catch(info => {
|
||||
console.log('Validate Failed:', info);
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
name="form_in_modal"
|
||||
initialValues={initialData}
|
||||
>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label="Name"
|
||||
rules={[{required: true, message: 'Please input Name!'}]}
|
||||
>
|
||||
<Input/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="username"
|
||||
label="Username"
|
||||
rules={[{required: true, message: 'Please input Username!'}]}
|
||||
>
|
||||
<Input/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="status"
|
||||
label="Status"
|
||||
|
||||
rules={[{required: true, message: 'Please select Status!'}]}
|
||||
>
|
||||
<Select
|
||||
showSearch
|
||||
placeholder="Select Status"
|
||||
optionFilterProp="children"
|
||||
filterOption={(input, option) =>
|
||||
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
filterSort={(optionA, optionB) =>
|
||||
optionA.children.toLowerCase().localeCompare(optionB.children.toLowerCase())
|
||||
}
|
||||
>
|
||||
{dataStatus.map(it => {
|
||||
return <Option value={it}>{it}</Option>
|
||||
})}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
70
src/pages/Product/Product.js
Normal file
70
src/pages/Product/Product.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, Row, Tabs} from "antd";
|
||||
import {FilterOutlined, PlusSquareOutlined,} from "@ant-design/icons";
|
||||
import {BreadcumbComponent} from "../../component/BreadcumbComponent";
|
||||
import {Pulsa} from "./Pulsa";
|
||||
|
||||
const {TabPane} = Tabs;
|
||||
const {Search} = Input;
|
||||
|
||||
export const Product = () => {
|
||||
const callback = (key) => {
|
||||
console.log(key);
|
||||
};
|
||||
const routeData = [
|
||||
{
|
||||
route: "/app/home",
|
||||
name: "Home",
|
||||
},
|
||||
{
|
||||
route: "/app/product",
|
||||
name: <span style={{fontWeight: 'bold'}}>Product</span>,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<BreadcumbComponent data={routeData}/>
|
||||
<Card>
|
||||
<Row style={{marginBottom: 20}}>
|
||||
<Col span={12}>
|
||||
<Button>
|
||||
<FilterOutlined/>
|
||||
Filter
|
||||
</Button>
|
||||
</Col>
|
||||
<Col span={12} style={{textAlign: "right"}}>
|
||||
<Search
|
||||
placeholder="input search text"
|
||||
style={{width: 200, marginRight: 10}}
|
||||
/>
|
||||
<Button>
|
||||
<PlusSquareOutlined/> New
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
onChange={callback}
|
||||
size="default"
|
||||
tabBarGutter="50"
|
||||
>
|
||||
<TabPane tab="Pulsa" key="1">
|
||||
<Pulsa/>
|
||||
</TabPane>
|
||||
<TabPane tab="Game Voucher" key="2">
|
||||
Game Voucher
|
||||
</TabPane>
|
||||
<TabPane tab="Product" key="3">
|
||||
Product
|
||||
</TabPane>
|
||||
<TabPane tab="Prduct" key="4">
|
||||
Prduct
|
||||
</TabPane>
|
||||
<TabPane tab="Prdct" key="5">
|
||||
Prdct
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
100
src/pages/Product/Pulsa.js
Normal file
100
src/pages/Product/Pulsa.js
Normal file
@@ -0,0 +1,100 @@
|
||||
import React from "react";
|
||||
import {Button, Space, Table, Tag} from "antd";
|
||||
|
||||
export const Pulsa = () => {
|
||||
const columns = [
|
||||
{
|
||||
title: "Kode",
|
||||
dataIndex: "kode",
|
||||
key: "kode",
|
||||
},
|
||||
{
|
||||
title: "Produk",
|
||||
dataIndex: "produk",
|
||||
key: "produk",
|
||||
},
|
||||
{
|
||||
title: "Harga Beli",
|
||||
dataIndex: "harga_beli",
|
||||
key: "harga_beli",
|
||||
},
|
||||
,
|
||||
{
|
||||
title: "Harga Jual",
|
||||
dataIndex: "harga_jual",
|
||||
key: "harga_beli",
|
||||
},
|
||||
{
|
||||
title: "Gangguan",
|
||||
dataIndex: "gangguan",
|
||||
key: "gangguan",
|
||||
},
|
||||
{
|
||||
title: "Tersedia",
|
||||
dataIndex: "tersedia",
|
||||
key: "tersedia",
|
||||
},
|
||||
{
|
||||
title: "Action",
|
||||
key: "action",
|
||||
render: (text, record) => (
|
||||
<Space size="middle">
|
||||
<Button>Edit</Button>
|
||||
<Button>Delete</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
const dataSource = [
|
||||
{
|
||||
key: "1",
|
||||
kode: "BROP2",
|
||||
produk: "DATA AXIS 2GB-60HR",
|
||||
harga_beli: "Rp.10.000",
|
||||
harga_beli: "Rp.10.000",
|
||||
harga_jual: "Rp.40.000",
|
||||
gangguan: <Tag color="processing">Active</Tag>,
|
||||
tersedia: <Tag color="processing">Ya</Tag>,
|
||||
},
|
||||
{
|
||||
key: "2",
|
||||
kode: "-",
|
||||
produk: "-",
|
||||
harga_beli: "-",
|
||||
harga_beli: "-",
|
||||
harga_jual: "-",
|
||||
gangguan: <Tag color="#E3E8EE" style={{color: '#4F566B'}}>Gangguan</Tag>,
|
||||
tersedia: <Tag color="#E3E8EE" style={{color: '#4F566B'}}>Tidak</Tag>,
|
||||
},
|
||||
{
|
||||
key: "3",
|
||||
kode: "-",
|
||||
produk: "-",
|
||||
harga_beli: "-",
|
||||
harga_beli: "-",
|
||||
harga_jual: "-",
|
||||
gangguan: <Tag color="processing">Active</Tag>,
|
||||
tersedia: <Tag color="processing">Ya</Tag>,
|
||||
},
|
||||
{
|
||||
key: "4",
|
||||
kode: "-",
|
||||
produk: "-",
|
||||
harga_beli: "-",
|
||||
harga_beli: "-",
|
||||
harga_jual: "-",
|
||||
gangguan: <Tag color="processing">Active</Tag>,
|
||||
tersedia: <Tag color="processing">Ya</Tag>,
|
||||
}
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
style={{textAlign: "center"}}
|
||||
columns={columns}
|
||||
dataSource={dataSource}
|
||||
bordered
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
127
src/pages/Transaction/Pulsa.js
Normal file
127
src/pages/Transaction/Pulsa.js
Normal file
@@ -0,0 +1,127 @@
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Dropdown, Menu, message, Modal, Row, Space,} from "antd";
|
||||
import {DownOutlined, TabletOutlined, UserOutlined} from "@ant-design/icons";
|
||||
|
||||
//const style = { background: "#0092ff", padding: "8px 0" };
|
||||
const gridStyle = {
|
||||
width: "18%",
|
||||
textAlign: "center",
|
||||
marginRight: "8px",
|
||||
marginBottom: "20px",
|
||||
};
|
||||
|
||||
export const Pulsa = () => {
|
||||
|
||||
function handleMenuClick(e) {
|
||||
message.info("Click on menu item.");
|
||||
console.log("click", e);
|
||||
}
|
||||
|
||||
const menu = (
|
||||
<Menu onClick={handleMenuClick}>
|
||||
<Menu.Item key="1" icon={<UserOutlined/>}>
|
||||
1st menu item
|
||||
</Menu.Item>
|
||||
<Menu.Item key="2" icon={<UserOutlined/>}>
|
||||
2nd menu item
|
||||
</Menu.Item>
|
||||
<Menu.Item key="3" icon={<UserOutlined/>}>
|
||||
3rd menu item
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
|
||||
function success() {
|
||||
Modal.success({
|
||||
content: 'some messages...some messages...',
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row>
|
||||
<span style={{fontWeight: "bold", marginBottom: "10px"}}>
|
||||
Sub-Category
|
||||
</span>
|
||||
</Row>
|
||||
<Row>
|
||||
<Space wrap>
|
||||
<Dropdown overlay={menu}>
|
||||
<Button
|
||||
style={{
|
||||
marginBottom: "20px",
|
||||
color: "grey",
|
||||
}}
|
||||
>
|
||||
<TabletOutlined/>
|
||||
Select sub-Category
|
||||
<DownOutlined/>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
</Space>
|
||||
</Row>
|
||||
<Row>
|
||||
<span style={{fontWeight: "bold", marginBottom: "10px"}}>
|
||||
Produk & Nominal
|
||||
</span>
|
||||
</Row>
|
||||
<Card>
|
||||
<Card.Grid style={gridStyle} onClick={success}>
|
||||
<span style={{color: "black"}}>DATA AXIS BRONET 2GB-60HR</span>
|
||||
<br/>
|
||||
<span style={{color: "grey", fontSize: 10}}>Harga : Rp.6.000</span>
|
||||
</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>
|
||||
<span style={{color: "black"}}>DATA AXIS BRONET 2GB-60HR</span>
|
||||
<br/>
|
||||
<span style={{color: "grey", fontSize: 10}}>Harga : Rp.6.000</span>
|
||||
</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>
|
||||
<span style={{color: "black"}}>DATA AXIS BRONET 2GB-60HR</span>
|
||||
<br/>
|
||||
<span style={{color: "grey", fontSize: 10}}>Harga : Rp.6.000</span>
|
||||
</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>
|
||||
<span style={{color: "black"}}>DATA AXIS BRONET 2GB-60HR</span>
|
||||
<br/>
|
||||
<span style={{color: "grey", fontSize: 10}}>Harga : Rp.6.000</span>
|
||||
</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>
|
||||
<span style={{color: "black"}}>DATA AXIS BRONET 2GB-60HR</span>
|
||||
<br/>
|
||||
<span style={{color: "grey", fontSize: 10}}>Harga : Rp.6.000</span>
|
||||
</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>
|
||||
<span style={{color: "black"}}>DATA AXIS BRONET 2GB-60HR</span>
|
||||
<br/>
|
||||
<span style={{color: "grey", fontSize: 10}}>Harga : Rp.6.000</span>
|
||||
</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>
|
||||
<span style={{color: "black"}}>DATA AXIS BRONET 2GB-60HR</span>
|
||||
<br/>
|
||||
<span style={{color: "grey", fontSize: 10}}>Harga : Rp.6.000</span>
|
||||
</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>
|
||||
<span style={{color: "black"}}>DATA AXIS BRONET 2GB-60HR</span>
|
||||
<br/>
|
||||
<span style={{color: "grey", fontSize: 10}}>Harga : Rp.6.000</span>
|
||||
</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>
|
||||
<span style={{color: "black"}}>DATA AXIS BRONET 2GB-60HR</span>
|
||||
<br/>
|
||||
<span style={{color: "grey", fontSize: 10}}>Harga : Rp.6.000</span>
|
||||
</Card.Grid>
|
||||
<Card.Grid style={gridStyle}>
|
||||
<span style={{color: "black"}}>DATA AXIS BRONET 2GB-60HR</span>
|
||||
<br/>
|
||||
<span style={{color: "grey", fontSize: 10}}>Harga : Rp.6.000</span>
|
||||
</Card.Grid>
|
||||
</Card>
|
||||
<Col style={{textAlign: "right"}}>
|
||||
<Button style={{backgroundColor: "#2D9CDB", color: "white"}}>
|
||||
Beli Sekarang
|
||||
</Button>
|
||||
</Col>
|
||||
</div>
|
||||
);
|
||||
};
|
67
src/pages/Transaction/Transaction.js
Normal file
67
src/pages/Transaction/Transaction.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Input, Row, Tabs} from "antd";
|
||||
import {FilterOutlined,} from "@ant-design/icons";
|
||||
import {BreadcumbComponent} from "../../component/BreadcumbComponent";
|
||||
import {Pulsa} from "./Pulsa";
|
||||
|
||||
const {TabPane} = Tabs;
|
||||
const {Search} = Input;
|
||||
|
||||
export const Transaction = () => {
|
||||
const callback = (key) => {
|
||||
console.log(key);
|
||||
};
|
||||
const routeData = [
|
||||
{
|
||||
route: "/app/home",
|
||||
name: "Home",
|
||||
},
|
||||
{
|
||||
route: "/app/transaction",
|
||||
name: <span style={{fontWeight: 'bold'}}>Transaction</span>,
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div>
|
||||
<BreadcumbComponent data={routeData} text=""/>
|
||||
<Card>
|
||||
<Row style={{marginBottom: 20}}>
|
||||
<Col span={12}>
|
||||
<Button>
|
||||
<FilterOutlined/>
|
||||
Filter
|
||||
</Button>
|
||||
</Col>
|
||||
<Col span={12} style={{textAlign: "right"}}>
|
||||
<Search
|
||||
placeholder="input search text"
|
||||
style={{width: 200, marginRight: 10}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
onChange={callback}
|
||||
size="default"
|
||||
tabBarGutter="50"
|
||||
>
|
||||
<TabPane tab="Pulsa" key="1">
|
||||
<Pulsa/>
|
||||
</TabPane>
|
||||
<TabPane tab="Game Voucher" key="2">
|
||||
Game Voucher
|
||||
</TabPane>
|
||||
<TabPane tab="Product" key="3">
|
||||
Product
|
||||
</TabPane>
|
||||
<TabPane tab="Prduct" key="4">
|
||||
Prduct
|
||||
</TabPane>
|
||||
<TabPane tab="Prdct" key="5">
|
||||
Prdct
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
Reference in New Issue
Block a user