Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accounts merchants add #17

Merged
merged 3 commits into from May 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18,368 changes: 0 additions & 18,368 deletions package-lock.json

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -11,7 +11,7 @@
"classnames": "2.2.6",
"history": "4.9.0",
"i18next": "^19.4.1",
"moment": "^2.24.0",
"moment": "2.24.0",
"moment-timezone": "^0.5.28",
"perfect-scrollbar": "1.4.0",
"prop-types": "15.7.2",
Expand Down
10 changes: 4 additions & 6 deletions src/assets/css/duocun.css
@@ -1,10 +1,8 @@

/** Common */
/** textarea */
.dc-full-textarea {
width: 100%;
}
/** table */
table.dc-table {
min-width: 750
}
}
.dc-full, .dc-full-select, .dc-full-textarea {
width: 100%
}
21 changes: 11 additions & 10 deletions src/services/api/ApiAccountService.js
@@ -1,18 +1,16 @@
import ApiService from "services/api/ApiService";
import { buildPaginationQuery } from "helper/index";
export default {
getAccountList: (page, pageSize, search = "", sort = []) => {
getAccountList: (page, pageSize, {username, type}, sort = []) => {
let query = {};
if (!search) {
query.query = buildPaginationQuery(page, pageSize, {}, [], sort);
} else {
const condition = {
username: {
$regex: search,
},
};
query.query = buildPaginationQuery(page, pageSize, condition, [], sort);
let conditions = {};
if (username) {
conditions.username = { $regex: username };
}
if (type) {
conditions.type = type;
}
query.query = buildPaginationQuery(page, pageSize, conditions, [], sort);
return ApiService.v2().get("accounts", query);
},
getAccountAllKeyword: (keyword = "") => {
Expand Down Expand Up @@ -41,4 +39,7 @@ export default {
);
return ApiService.v2().get("accounts", query);
},
createAccount: (accountData = {}) => {
return ApiService.v2().post("accounts", accountData);
},
};
5 changes: 4 additions & 1 deletion src/services/api/ApiMerchantService.js
Expand Up @@ -14,5 +14,8 @@ export default {
query.query = buildPaginationQuery(page, pageSize, condition, [], sort);
}
return ApiService.v2().get("merchants", query);
}
},
createMerchant: (merchantData = {}) => {
return ApiService.v2().post("merchants", merchantData);
},
};
237 changes: 233 additions & 4 deletions src/views/Accounts/AccountsForm.js
@@ -1,8 +1,237 @@
import React from "react";
const AccountForm = () => {
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";

import { Save as SaveIcon, FormatListBulleted as FormatListBulletedIcon } from "@material-ui/icons";
import { TextField, Button, Checkbox,
Select, MenuItem, InputLabel, FormControl, FormControlLabel } from "@material-ui/core";
import { Alert } from "@material-ui/lab"

import GridContainer from "components/Grid/GridContainer.js";
import GridItem from "components/Grid/GridItem.js";
import Card from "components/Card/Card.js";
import CardHeader from "components/Card/CardHeader.js";
import CardBody from "components/Card/CardBody.js";
import CardFooter from "components/Card/CardFooter.js";

import EditSkeleton from "../Common/EditSkeleton";
import ApiAccountService from "services/api/ApiAccountService";

const defaultAccountsModelState = {
_id: 'new',
username: "",
imageurl: "",
realm: "",
sex: "",
openId: "",
type: "merchant",
balance: 0,
phone: "",
created: "",
verificationCode: "",
verified: true,
attributes: []
}
const AccountsForm = ({}) => {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [processing, setProcessing] = useState(false);

// for model
const [model, setModel] = useState(defaultAccountsModelState);
const [alert, setAlert] = useState({ message: "", severity: "info" });

const _ATTRIBUTES = {
I: "INDOOR",
G: "GARDENING",
R: "ROOFING",
O: "OFFICE",
P: "PLAZA",
H: "HOUSE",
C: "CONDO",
}

//////////////////// For data fetch
const getAccountData = () => {

}

/////////////////// For render and events

const _renderUserInfo = ()=> {
return <React.Fragment>
<GridItem xs={12}>
<h5>{t("Basic Information")}</h5>
</GridItem>
<GridItem xs={12} lg={12} >
<FormControl className="dc-full-select">
<InputLabel id="merchant-type-label">Type</InputLabel>
<Select required labelId="merchant-type-label" id="account-type"
value={model.type} onChange={ e => setModel({...model, type: e.target.value})} >
<MenuItem value={'merchant'}>Merchant</MenuItem>
<MenuItem value={'driver'}>Driver</MenuItem>
<MenuItem value={'client'}>Client</MenuItem>
<MenuItem value={'system'}>System</MenuItem>
<MenuItem value={'freight'}>Freight</MenuItem>
</Select>
</FormControl>
</GridItem>
<GridItem xs={12} md={6} lg={6}>
<TextField id="account-username" label={`${t("Username")}`}
required className="dc-full" value={model.username}
onChange={e => { setModel({ ...model, username: e.target.value }); }}
/>
</GridItem>
<GridItem xs={12} md={6} lg={6}>
<TextField id="account-imageurl" label={`${t("ImageUrl")}`}
disabled className="dc-full" value={model.imageurl}
onChange={e => { setModel({ ...model, imageurl: e.target.value }); }}
/>
</GridItem>
<GridItem xs={12} md={6} lg={6}>
<TextField id="account-realm" label={`${t("Realm")}`}
disabled className="dc-full" value={model.realm}
onChange={e => { setModel({ ...model, realm: e.target.value }); }}
/>
</GridItem>
<GridItem xs={12} md={6} lg={6}>
<TextField id="account-sex" label={`${t("Sex")}`}
disabled className="dc-full" value={model.sex}
onChange={e => { setModel({ ...model, sex: e.target.value }); }}
/>
</GridItem>
<GridItem xs={12} md={6} lg={6}>
<TextField id="account-phone" label={`${t("Phone")}`}
disabled className="dc-full" value={model.phone}
onChange={e => { setModel({ ...model, phone: e.target.value }); }}
/>
</GridItem>
</React.Fragment>
}
const _attributeClick = (e, _key) => {
const attr = model.attributes || [];
if (e.target.checked) {
if (attr.indexOf(_key) < 0 ) {
attr.push(_key);
}
} else {
const index = attr.indexOf(_key);
if (index >= 0 ) {
attr.splice(index, 1);
}
}
setModel({...model, attributes: attr});
}
const _renderAttributes = () => {
return <React.Fragment>
<GridItem xs={12}>
<h5>{t("Attributes")}</h5>
</GridItem>
<GridItem xs={12} lg={12} >
<GridContainer>
{
Object.keys(_ATTRIBUTES).map( _key => {
return <GridItem xs={6} lg={6} >
<FormControlLabel
control={<Checkbox checked={model.attributes.indexOf(_key)>=0}
onChange={(e) => _attributeClick(e, _key)} color="primary" />}
label={_ATTRIBUTES[_key]||_key}
labelPlacement="end"
/>
</GridItem>
})
}
</GridContainer>
</GridItem>
</React.Fragment>
}

const renderRight = () => {
return <GridContainer>
{_renderAttributes()}
</GridContainer>
}
const renderLeft = () => {
return <GridContainer>
{_renderUserInfo()}
</GridContainer>
}
const removeAlert = () => {
setAlert({
message: "",
severity: "info"
});
};


////////////////////////////////////
// For submit
const saveModel = () => {
setProcessing(true);
ApiAccountService.createAccount(model).then(
({ data }) => {
setProcessing(false);
if ( data.code === "success" ) {
// success
setAlert({
message: "Created success!",
severity: "success"
});
} else {
// failure
setAlert({
message: data.data,
severity: "error"
});
}
}
);
}

return (
<div>Account Form</div>
<GridContainer>
<GridItem xs={12} lg={12}>
<Card>
<CardHeader color="primary">
{loading && <h4>{t("Merchants")}</h4>}
{!loading && (
<h4>
{model._id && model._id !== "new"
? t("Edit Account") + ": " + model.name
: t("Add Account")}
</h4>
)}
</CardHeader>
<CardBody>
{loading && <EditSkeleton />}
{!!alert.message && (
<Alert severity={alert.severity} onClose={removeAlert}>
{alert.message}
</Alert>
)}
{!loading && <GridContainer>
<GridItem xs={12} md={6} lg={6}>{renderLeft()}</GridItem>
<GridItem xs={12} md={6} lg={6}>{renderRight()} </GridItem>
</GridContainer>}
</CardBody>
<CardFooter direction="row-reverse">
<GridContainer>
<GridItem xs={12} >
<Button color="primary" variant="contained"
disabled={loading || processing || !model.username || !model.type }
onClick={saveModel} >
<SaveIcon /> {t("Save")}
</Button>
&nbsp;&nbsp;&nbsp;&nbsp;
<Button variant="contained" href="../Merchants">
<FormatListBulletedIcon /> {t("Back")}
</Button>
</GridItem>
</GridContainer>
</CardFooter>
</Card>
</GridItem>
</GridContainer>
);
};

export default AccountForm;
export default AccountsForm;
19 changes: 12 additions & 7 deletions src/views/Accounts/AccountsTable.js
@@ -1,8 +1,9 @@
import React, { useState, useEffect } from "react";
import React from "react";
import PropTypes from "prop-types";
import { useTranslation } from "react-i18next";

import { Avatar, Chip, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TableSortLabel } from "@material-ui/core";
import { Avatar, Chip, Table, TableBody, TableCell, TableContainer,
TableHead, TableRow, TableSortLabel, Switch } from "@material-ui/core";
import LocalMallIcon from "@material-ui/icons/LocalMall";

import TableBodySkeleton from "components/Table/TableBodySkeleton";
Expand Down Expand Up @@ -41,7 +42,7 @@ export default function AccountsTable({ accounts, rowsPerPage, toggleSort, sort,
return (
<React.Fragment>
{rows.map((row, idx) => (
<TableRow key={idx}>
<TableRow key={`${row._id}_${idx}`}>
<TableCell>{page * rowsPerPage + idx + 1}</TableCell>
<TableCell>
<Avatar
Expand All @@ -56,14 +57,18 @@ export default function AccountsTable({ accounts, rowsPerPage, toggleSort, sort,
<TableCell>{row.type}</TableCell>
<TableCell>{row.phone}</TableCell>
<TableCell>{row.balance}</TableCell>
<TableCell>{row.email}</TableCell>
<TableCell>
<Switch checked={row.verified} name="checkedA" color="primary"
inputProps={{ 'aria-label': 'primary checkbox' }}
/>
</TableCell>
<TableCell>
{row.roles &&
row.roles
.map(item => ROLE_MAPPING[item] || item)
.map(item => (
// eslint-disable-next-line react/jsx-key
<React.Fragment>
<React.Fragment key={`${item}`}>
<Chip variant="outlined" size="small" label={item} />
<br />
</React.Fragment>
Expand All @@ -75,7 +80,7 @@ export default function AccountsTable({ accounts, rowsPerPage, toggleSort, sort,
.map(item => ATTRIBUTES_MAPPING[item] || item)
.map(item => (
// eslint-disable-next-line react/jsx-key
<React.Fragment>
<React.Fragment key={`${item}`}>
<Chip variant="outlined" size="small" label={item} />
<br />
</React.Fragment>
Expand Down Expand Up @@ -125,7 +130,7 @@ export default function AccountsTable({ accounts, rowsPerPage, toggleSort, sort,
</TableCell>
<TableCell onClick={() => { toggleSort && toggleSort("email"); }}
style={{ cursor: "pointer" }} >
{t("Email")} {renderSort("email")}
{t("Verified")} {renderSort("verified")}
</TableCell>
<TableCell>{t("Roles")}</TableCell>
<TableCell>{t("Attributes")}</TableCell>
Expand Down
2 changes: 1 addition & 1 deletion src/views/Accounts/AccountsTablePage.js
Expand Up @@ -45,7 +45,7 @@ export default function AccountsTablePage({ location }) {
}, [page, rowsPerPage, sort]);

const updateData = () => {
ApiAccountService.getAccountList(page, rowsPerPage, query, [sort]).then(
ApiAccountService.getAccountList(page, rowsPerPage, {username:query}, [sort]).then(
({ data }) => {
setAccounts(data.data);
setTotalRows(data.count);
Expand Down
10 changes: 10 additions & 0 deletions src/views/Common/EditSkeleton.js
Expand Up @@ -30,5 +30,15 @@ const EditSkeleton = () => (
</GridItem>
</React.Fragment>
);
export const EditSkeletonShort = () => (
<React.Fragment>
<GridItem xs={12} lg={12}>
<Skeleton height={48} />
</GridItem>
<GridItem xs={12} lg={12}>
<Skeleton height={48} />
</GridItem>
</React.Fragment>
);

export default EditSkeleton;