PhyoThandar 3 years ago
parent
commit
dc6bf4bd93

+ 2 - 1
.eslintrc

@@ -28,6 +28,7 @@
     "react/jsx-handler-names": 0,
     "react/jsx-fragments": 0,
     "react/no-unused-prop-types": 0,
-    "import/export": 0
+    "import/export": 0,
+    "prettier/prettier": 0
   }
 }

+ 129 - 1
README.md

@@ -1,3 +1,131 @@
 # mokkon-reactjs
 
-Mokkon's reactjs components
+Mokkon's reactjs components
+
+## MkForm 
+
+### Props
+
+| Name        | Type           | Default  | Description
+| ------------- |-------------| -----:| --------: |
+| fields      | Array of field object |  | Form fields 
+| data      | object      |   | Form data |
+| actions | Array of action object      |     |
+
+
+**Field object**
+
+| Name        | Type           | Default  | Description
+| ------------- |-------------| -----:| -------- |
+| field_name      | string |  | Field name 
+| label      | string      |  | Field label |
+| type      | string      |  | Field type <ul><li>dropdown</li><li>text_string</li><li>Propstext_number</li><li>text_multiline</li><li>list</li><li>photo_list</li><li>date</li><li>time</li></ul>|
+| options      | Array of selection object      |  | Data objects for dropdown or autocomplete |
+| can_create      | boolean      |  | To handle adding new object from dropdown or autocomplete |
+| readonly      | boolean      |  | To handle for not editable form |
+| option_label_field      | string      |  | Field name to get label of option in dropdown |
+
+ 
+ **Example of field object** 
+```javascript
+    [ 
+        {
+        "type":"string",
+        "label":"string",
+        "field_name":"string",
+        "options":[],
+        "can_create":boolean,
+        "readonly":boolean,
+        "option_label_field":"string",
+        } 
+    ]
+```
+
+**Action object**
+
+| Name        | Type           | Default  | Description
+| ------------- |-------------| -----| -------- |
+| label      | string      |  | Action label |
+| icon      | icon      |  | Action icon |
+| callback      | function      |  | Action ( edit, delete, etc..) |
+| status      | string      |  | Form data status |
+
+ **Example of action object** 
+```javascript
+    { 
+    "label": "string",
+    "icon": icon,
+    "callback": () => {}
+     }
+ ```
+
+**Data**
+
+Example of data object 
+```javascript
+    { 
+   "field_name":"value",
+   "field_name":"value",
+     }
+ ```
+
+
+## MkTable
+
+**Props**
+
+
+| Name        | Type           | Default  | Description
+| ------------- |-------------| -----| -------- |
+| headers      | Array of header object |  | Table headers
+| data      | object      |   | Form data |
+| onActions | Array of action callback      |     | Return function with data or event
+| actions | Array of action object      |     |
+| title | string      |     |Item title (item, category,etc..)
+| order | string      | asc    | Order (asc, desc)
+| orderBy | string      |   name  | Order by 
+| rowsPerPage |number      |     | Number of rows in page
+| noMoreToLoad | boolean     |     |To handle end of data
+| isLoading | boolean      |     | To Handle progressing
+| onChangePaginatePage | function      |     | To Change page number
+| onGetData | function      |     | To Get data list
+| onChangeRowPerPage | function      |     | To change number of rows in page
+| dense | boolean      |   true  | To handle table size
+
+ **Example of action object **
+```javascript
+    { 
+    "label": "string",
+    "icon": icon element,
+    "callback": () => {}
+     }
+```
+
+**Header object**
+
+| Name        | Type           | Default  | Description
+| ------------- |-------------| -----:| --------: |
+| id      | string |  | Field name of data object
+| numeric      | boolean      |   | To handle numeric or not |
+| disablePadding | boolean      |  |Table cell padding   
+| label      | string      |   | Label of Header |
+| width | Array of action object      | | Tablecell width   
+
+ **Example of header object **
+```javascript
+    [
+        {
+        'id': 'sr', 
+        'numeric': true,
+        'disablePadding': false,
+        'label': 'No.'
+        },
+        { 
+            'id': 'name',
+            'numeric': false,
+            'disablePadding': false,
+            'label': 'Name',
+            'width': '200px'
+        },
+  ]
+```

File diff suppressed because it is too large
+ 504 - 231
dist/index.js


File diff suppressed because it is too large
+ 0 - 0
dist/index.js.map


File diff suppressed because it is too large
+ 798 - 322
dist/index.modern.js


File diff suppressed because it is too large
+ 0 - 0
dist/index.modern.js.map


File diff suppressed because it is too large
+ 15815 - 30791
example/package-lock.json


+ 3 - 2
example/package.json

@@ -10,10 +10,11 @@
     "eject": "node ../node_modules/react-scripts/bin/react-scripts.js eject"
   },
   "dependencies": {
+    "@mokkon/reactjs": "file:..",
     "react": "file:../node_modules/react",
     "react-dom": "file:../node_modules/react-dom",
-    "react-scripts": "file:../node_modules/react-scripts",
-    "@mokkon/reactjs": "file:.."
+    "react-router-dom": "file:../node_modules/react-router-dom",
+    "react-scripts": "file:../node_modules/react-scripts"
   },
   "devDependencies": {
     "@babel/plugin-syntax-object-rest-spread": "^7.8.3"

+ 5 - 136
example/src/App.js

@@ -1,145 +1,14 @@
-import React from 'react'
-
-import { List, FieldList, TableTemplate, InfoPage } from '@mokkon/reactjs'
+import React from 'react';
 import '@mokkon/reactjs/dist/index.css'
-import { Grid } from '@material-ui/core'
-import EditIcon from '@material-ui/icons/Edit';
-import DeleteIcon from '@material-ui/icons/Delete';
-import SaveIcon from '@material-ui/icons/Save';
-import CancelIcon from '@material-ui/icons/Cancel';
+import ResponsiveDrawer from './components/ResponsiveDrawer';
 
 const App = () => {
-  const pediatricians = [
-    'Michael Lopez',
-    'Sally Tran',
-    'Brian Lu',
-    'Troy Sakulbulwanthana',
-    'Lisa Wellington',
-  ]
-
-  const psychiatrists = [
-    'Miguel Rodriduez',
-    'Cassady Campbell',
-    'Mike Torrence',
-  ]
-
-  const fields = [
-    { type: 'text_string', label: 'Name', fieldName: 'name' },
-    { type: 'text_multiline', label: 'Address', fieldName: 'address' },
-    { type: 'text_number', label: 'Latitude', fieldName: 'latitude' },
-    { type: 'text_number', label: 'Longitude', fieldName: 'longitude' },
-    { type: 'text_number', label: 'Max Variance', fieldName: 'max_variance' },
-    { type: 'text_number', label: 'Min Variance', fieldName: 'min_variance' },
-    { type: 'dropdown', label: 'Customer Name', fieldName: 'customer_name', options: [] },
-    // { type: 'checkbox', label: 'Customer Name', fieldName: 'customer_name', checkboxList: [{'label': },{}] },
-  ];
-
-  const data = {
-    delete_time: 0,
-    name: "Vendor 13",
-    update_time: 1610341578878,
-    updated_by: "Nine Nine",
-    updated_by_id: "kShMtHkcwTNjwm-lfzSBvAzdSo1J8dIpAz6_Ct85HPg",
-    status: 'requested'
-  }
-
-  const headCells = [
-    { id: 'id', numeric: true, disablePadding: false, label: 'No.' },
-    { id: 'name', numeric: true, disablePadding: false, label: 'Name' },
-  ];
-
-  const handleUpdate = (data) => {
-    console.log('update data :', data);
-  }
-
-  const handleDelete = (data) => {
-    console.log('delete data :', data);
-  }
-
-  const handleSave = (data) => {
-    console.log('save data :', data);
-  }
-
-  const handleCancel = (data) => {
-    console.log('cancel data :', data);
-  }
-  var actions = [
-    { "label": "edit", "action_type": "edit", "icon": <EditIcon /> },
-    { "label": "delete", "action_type": "delete", "callback": handleDelete, "icon": <DeleteIcon /> },
-    { "label": "save", "action_type": "save", "callback": handleSave, "icon": <SaveIcon /> },
-    { "label": "cancel", "action_type": "cancel", "callback": handleCancel, "icon": <CancelIcon /> },
-    // { "label": "delete invitation", "action_type": "delete_invitation", "callback": handleDeleteInvitation, "icon": "" },
-    // { "label": "approve member", "action_type": "approve_member", "callback": handleApprovedMember, "icon": "" },
-    // { "label": "disable member", "action_type": "disable_member", "callback": handleDisableMember, "icon": "" },
-    // { "label": "enable member", "action_type": "enable_member", "callback": handleEnableMember, "icon": "" },
-    // { "label": "invite member", "action_type": "invite_member", "callback": handleMemberInvite, "icon": "" },
-    // { "label": "", "action_type": "back_btn", "callback": handleBack, "icon": "" },
-
-  ];
-  var tableData = [data];
 
   return <div>
     <div className="root">
-      {/* <div className="listContainer">
-        <List groupName="Pediatricians" members={pediatricians} />
-      </div>
-      <div className="listContainer">
-        <List groupName="Psychiatrists" members={psychiatrists} />
-      </div> */}
-
-      {/*field list */}
-      {/* <div className="listContainer">
-        <Grid container>
-          <Grid item xs={12} sm={6}>
-            <FieldList
-              fields={fields}
-              updateData={data}
-              buttonColor={'#f05f40'}
-              // onUpdate={() => console.log('on update')}
-              // onCancel={() => console.log('on cancel')}
-              // onApproved={() => console.log('on approved')}
-              // onCreate={() => console.log('on create')}
-              // onInvite={() => console.log('on invite')}
-            ></FieldList>
-          </Grid>
-        </Grid>
-      </div> */}
-
-      {/*info page */}
-      <div className="listContainer">
-        <Grid container>
-          <Grid item xs={12} sm={6}>
-            <InfoPage
-              displayFields={fields}
-              updateData={data}
-              buttonColor={'#f05f40'}
-              actions={actions}
-            // onUpdate={() => console.log('on update')}
-            // onCancel={() => console.log('on cancel')}
-            // onApproved={() => console.log('on approved')}
-            // onCreate={() => console.log('on create')}
-            // onInvite={() => console.log('on invite')}
-            ></InfoPage>
-          </Grid>
-        </Grid>
-      </div>
-
-      {/*table template */}
-      {/* <div className="listContainer">
-        <TableTemplate
-          headers={headCells}
-          data={tableData}
-          page={0}
-          rowsPerPage={10}
-          order={'asc'}
-          orderBy={'name'}
-          onUpdateData={(value, data) => console.log('table update data')}
-          onReloadData={() => console.log('table reload data')}
-          onChangeRowsPerPage={(v) => console.log('table change row per page')}
-          onChangePage={(page) => console.log('table change page')}
-        ></TableTemplate>
-      </div> */}
-    </div>  </div>
+      <ResponsiveDrawer></ResponsiveDrawer>
+    </div>
+  </div>
 }
 
 export default App

+ 123 - 0
example/src/components/MkFormPage.js

@@ -0,0 +1,123 @@
+import React from 'react'
+
+import { MkForm } from '@mokkon/reactjs'
+import '@mokkon/reactjs/dist/index.css'
+import { Button, Dialog, DialogContent, DialogTitle, Grid } from '@material-ui/core'
+import EditIcon from '@material-ui/icons/Edit';
+import DeleteIcon from '@material-ui/icons/Delete';
+import SaveIcon from '@material-ui/icons/Save';
+import CancelIcon from '@material-ui/icons/Cancel';
+
+const MkFormPage = () => {
+  const [open, setOpen] = React.useState(false);
+
+  const handleClickOpen = () => {
+    setOpen(true);
+  };
+
+  const handleClose = () => {
+    setOpen(false);
+  };
+
+  const fields = [
+    { type: 'text_string', label: 'Name', field_name: 'name' },
+    { type: 'text_multiline', label: 'Address', field_name: 'address' },
+    { type: 'text_number', label: 'Latitude', field_name: 'latitude' },
+    { type: 'text_number', label: 'Longitude', field_name: 'longitude' },
+    { type: 'text_number', label: 'Max Variance', field_name: 'max_variance' },
+    { type: 'text_number', label: 'Min Variance', field_name: 'min_variance' },
+    {
+      type: 'dropdown', label: 'Customer Name', field_name: 'customer_name', option_label_field: "name", can_create: true, options: [
+        { name: 'Name1' }, { name: 'Name2' }, { name: 'Name3' }, { name: 'Name4' }
+      ]
+    },
+  ];
+
+  const data = {
+    delete_time: 0,
+    name: "Vendor 13",
+    address: "address",
+    update_time: 1610341578878,
+    updated_by: "Nine Nine",
+    updated_by_id: "kShMtHkcwTNjwm-lfzSBvAzdSo1J8dIpAz6_Ct85HPg",
+    // status: 'joined'
+  }
+
+  const handleDelete = (e, data) => {
+    console.log('delete data :', data);
+    setOpen(false);
+  }
+
+  const handleSave = (e, data) => {
+    console.log('save data :', data);
+    setOpen(false);
+  }
+
+  const handleCancel = (e, data) => {
+    console.log('cancel data :', data);
+    setOpen(false);
+  }
+
+  var actions = [
+    { "label": "edit", "action_type": "edit", "icon": <EditIcon />, "callback": (e, d) => { handleSave(e, d) } },
+    { "label": "delete", "action_type": "delete", "callback": (e, d) => { handleDelete(e, d) }, "icon": <DeleteIcon /> },
+    { "label": "save", "action_type": "save", "callback": (e, d) => { handleSave(e, d) }, "icon": <SaveIcon /> },
+    { "label": "cancel", "action_type": "cancel", "callback": (e, d) => { handleCancel(e, d) }, "icon": <CancelIcon /> },
+    { "label": "delete invitation", "action_type": "delete_invitation", "callback": (e, d) => { handleCancel() }, "icon": "", status: "invited" },
+    { "label": "MkFormrove member", "action_type": "MkFormrove_member", "callback": (e, d) => { handleCancel(e, d) }, "icon": "", status: "joined" },
+    { "label": "disable member", "action_type": "disable_member", "callback": (e, d) => { handleCancel(e, d) }, "icon": "", status: "joined" },
+    { "label": "enable member", "action_type": "enable_member", "callback": (e, d) => { handleCancel(e, d) }, "icon": "", status: "disabled" },
+    { "label": "invite member", "action_type": "invite_member", "callback": (e, d) => { handleCancel(e, d) }, "icon": "", status: "requested" },
+
+  ];
+
+  return (
+    <div className="root">
+      <Grid container>
+        <Grid item xs={12}>
+          <MkForm
+            fields={fields}
+            data={data}
+            buttonColor={'#f05f40'}
+            actions={actions}
+            onDropdownCreateNew={(data) => { console.log(data) }}
+          ></MkForm>
+        </Grid>
+      </Grid>
+      <Grid container
+        direction="row"
+        justify="center"
+        alignItems="center" >
+        <Grid item xs={12}>
+          <Button variant="outlined" color="primary" onClick={handleClickOpen}>
+            Open alert dialog with MkForm
+          </Button>
+          <Dialog
+            open={open}
+            onClose={handleClose}
+            aria-labelledby="alert-dialog-title"
+            aria-describedby="alert-dialog-description"
+          >
+            <DialogTitle id="alert-dialog-title">{"Mokkon MkForm"}</DialogTitle>
+            <DialogContent>
+              <Grid container>
+                <Grid item xs={12}>
+                  <MkForm
+                    fields={fields}
+                    data={data}
+                    buttonColor={'#f05f40'}
+                    actions={actions}
+                    onDropdownCreateNew={(data) => { console.log(data) }}
+                  ></MkForm>
+                </Grid>
+              </Grid>
+            </DialogContent>
+          </Dialog>
+        </Grid>
+      </Grid>
+
+    </div>
+  );
+}
+
+export default MkFormPage

+ 74 - 0
example/src/components/MkTablePage.js

@@ -0,0 +1,74 @@
+import React from 'react'
+import { MkTable } from '@mokkon/reactjs'
+import '@mokkon/reactjs/dist/index.css';
+import { Grid } from '@material-ui/core';
+import theme from '../theme';
+
+function createData(name, calories, fat, carbs, protein) {
+  return { name, calories, fat, carbs, protein };
+}
+
+const rows = [
+  createData('Cupcake', 305, 3.7, 67, 4.3),
+  createData('Donut', 452, 25.0, 51, 4.9),
+  createData('Eclair', 262, 16.0, 24, 6.0),
+  createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
+  createData('Gingerbread', 356, 16.0, 49, 3.9),
+  createData('Honeycomb', 408, 3.2, 87, 6.5),
+  createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
+  createData('Jelly Bean', 375, 0.0, 94, 0.0),
+  createData('KitKat', 518, 26.0, 65, 7.0),
+  createData('Lollipop', 392, 0.2, 98, 0.0),
+  createData('Marshmallow', 318, 0, 81, 2.0),
+  createData('Nougat', 360, 19.0, 9, 37.0),
+  createData('Oreo', 437, 18.0, 63, 4.0),
+];
+
+const MkTablePage = (props) => {
+  const [page, setPage] = React.useState(0);
+  const [rowsPerPage, setRowsPerPage] = React.useState(10);
+
+  const headCells = [
+    { id: 'sr', numeric: true, disablePadding: false, label: 'No.' },
+    { id: 'name', numeric: false, disablePadding: false, label: 'Name', width: '200px' },
+  ];
+
+  var actions = [{ "action_name": "delete", "display_name": "Delete", }];
+
+  const handleChangePaginatePage = (v) => {
+    setPage(v);
+    console.log('handleChangePaginatePage :', page);
+  }
+
+  const handleRowPerPage = (v) => {
+    setRowsPerPage(v);
+    console.log('handleRowPerPage :', v);
+  }
+
+  return (
+    <div className="root">
+      {/*table template */}
+      <Grid container>
+        <Grid item xs={8}>
+          <MkTable
+            theme={theme}
+            headers={headCells}
+            data={rows}
+            page={page}
+            rowsPerPage={rowsPerPage}
+            order={'asc'}
+            orderBy={'name'}
+            actions={actions}
+            noMoreToLoad={true}
+            onUpdateDataRow={(d) => { console.log('onUpdateDataRow: ', d) }}
+            onChangePaginatePage={(newPage) => { handleChangePaginatePage(newPage) }}
+            onGetData={() => { }}
+            onChangeRowPerPage={(rowPerPage) => { handleRowPerPage(rowPerPage) }}
+          ></MkTable>
+        </Grid>
+
+      </Grid>
+    </div>);
+}
+
+export default (MkTablePage);

+ 171 - 0
example/src/components/ResponsiveDrawer.js

@@ -0,0 +1,171 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import AppBar from '@material-ui/core/AppBar';
+import CssBaseline from '@material-ui/core/CssBaseline';
+import Divider from '@material-ui/core/Divider';
+import Drawer from '@material-ui/core/Drawer';
+import Hidden from '@material-ui/core/Hidden';
+import IconButton from '@material-ui/core/IconButton';
+import List from '@material-ui/core/List';
+import ListItem from '@material-ui/core/ListItem';
+import ListItemText from '@material-ui/core/ListItemText';
+import MenuIcon from '@material-ui/icons/Menu';
+import Toolbar from '@material-ui/core/Toolbar';
+import Typography from '@material-ui/core/Typography';
+import { makeStyles, useTheme } from '@material-ui/core/styles';
+import MkFormPage from './MkFormPage';
+import { Route, Router, Switch } from 'react-router-dom';
+import WelcomPage from './WelcomPage';
+import { createBrowserHistory } from 'history';
+import MkTablePage from './MkTablePage';
+
+const browserHistory = createBrowserHistory();
+
+const drawerWidth = 240;
+
+const useStyles = makeStyles((theme) => ({
+  root: {
+    display: 'flex',
+  },
+  drawer: {
+    [theme.breakpoints.up('sm')]: {
+      width: drawerWidth,
+      flexShrink: 0,
+    },
+  },
+  appBar: {
+    [theme.breakpoints.up('sm')]: {
+      width: `calc(100% - ${drawerWidth}px)`,
+      marginLeft: drawerWidth,
+    },
+  },
+  menuButton: {
+    marginRight: theme.spacing(2),
+    [theme.breakpoints.up('sm')]: {
+      display: 'none',
+    },
+  },
+  // necessary for content to be below app bar
+  toolbar: theme.mixins.toolbar,
+  drawerPaper: {
+    width: drawerWidth,
+  },
+  content: {
+    flexGrow: 1,
+    padding: theme.spacing(3),
+  },
+}));
+
+function ResponsiveDrawer(props) {
+  const { window } = props;
+  const classes = useStyles();
+  const theme = useTheme();
+  const [mobileOpen, setMobileOpen] = React.useState(false);
+  const [menuName, setMenuName] = React.useState('');
+
+  const handleDrawerToggle = () => {
+    setMobileOpen(!mobileOpen);
+  };
+
+  const handleOnClick = (path) => {
+    setMenuName(path);
+    browserHistory.push(path);
+  }
+
+  const menus = [
+    {name: 'MkForm', path:'MkForm'},
+    {name: 'MkTable', path:'MkTable'}
+  ]
+
+  const drawer = (
+    <div>
+      <div className={classes.toolbar} ><Typography variant="h4">Mokkon</Typography></div>
+      <Divider />
+      <List>
+        {menus.map((menu, index) => (
+          <ListItem button key={menu.name} onClick={() => handleOnClick(menu.path)}>
+            <ListItemText primary={menu.name} />
+          </ListItem>
+        ))}
+      </List>
+
+
+    </div>
+  );
+
+  const container = window !== undefined ? () => window().document.body : undefined;
+
+  return (
+    <div className={classes.root}>
+      <CssBaseline />
+      <AppBar position="fixed" className={classes.appBar}>
+        <Toolbar>
+          <IconButton
+            color="inherit"
+            aria-label="open drawer"
+            edge="start"
+            onClick={handleDrawerToggle}
+            className={classes.menuButton}
+          >
+            <MenuIcon />
+          </IconButton>
+          <Typography variant="h6" noWrap>
+            {menuName}
+          </Typography>
+        </Toolbar>
+      </AppBar>
+
+      <nav className={classes.drawer} aria-label="mailbox folders">
+        {/* The implementation can be swapped with js to avoid SEO duplication of links. */}
+        <Hidden smUp implementation="css">
+          <Drawer
+            container={container}
+            variant="temporary"
+            anchor={theme.direction === 'rtl' ? 'right' : 'left'}
+            open={mobileOpen}
+            onClose={handleDrawerToggle}
+            classes={{
+              paper: classes.drawerPaper,
+            }}
+            ModalProps={{
+              keepMounted: true, // Better open performance on mobile.
+            }}
+          >
+            {drawer}
+          </Drawer>
+        </Hidden>
+        <Hidden xsDown implementation="css">
+          <Drawer
+            classes={{
+              paper: classes.drawerPaper,
+            }}
+            variant="permanent"
+            open
+          >
+            {drawer}
+          </Drawer>
+        </Hidden>
+      </nav>
+      <main className={classes.content}>
+        <div className={classes.toolbar} />
+        <Router history={browserHistory}>
+          <Switch>
+            <Route path="/" component={WelcomPage} exact />
+            <Route path="/MkForm" component={MkFormPage} />
+            <Route path="/MkTable" component={MkTablePage} />
+          </Switch>
+        </Router>
+      </main>
+    </div>
+  );
+}
+
+ResponsiveDrawer.propTypes = {
+  /**
+   * Injected by the documentation to work in an iframe.
+   * You won't need it on your project.
+   */
+  window: PropTypes.func,
+};
+
+export default ResponsiveDrawer;

+ 16 - 0
example/src/components/WelcomPage.js

@@ -0,0 +1,16 @@
+import { Typography } from '@material-ui/core';
+import React from 'react';
+
+class WelcomePage extends React.Component {
+
+    render() {
+        return (
+            <div>
+                <Typography variant="h3">Welcome !</Typography>
+            </div>
+        );
+    };
+}
+
+
+export default (WelcomePage);

+ 3 - 1
example/src/index.js

@@ -4,4 +4,6 @@ import React from 'react'
 import ReactDOM from 'react-dom'
 import App from './App'
 
-ReactDOM.render(<App />, document.getElementById('root'))
+ReactDOM.render(
+        <App />
+    , document.getElementById('root'))

File diff suppressed because it is too large
+ 25600 - 1
package-lock.json


+ 5 - 3
package.json

@@ -1,6 +1,6 @@
 {
   "name": "@mokkon/reactjs",
-  "version": "1.0.3",
+  "version": "1.1.0",
   "description": "Made with create-react-library",
   "author": "",
   "license": "MIT",
@@ -27,7 +27,6 @@
     "react": "^16.0.0"
   },
   "devDependencies": {
-    "microbundle-crl": "^0.13.10",
     "babel-eslint": "^10.0.3",
     "cross-env": "^7.0.2",
     "eslint": "^6.8.0",
@@ -41,6 +40,7 @@
     "eslint-plugin-react": "^7.17.0",
     "eslint-plugin-standard": "^4.0.1",
     "gh-pages": "^2.2.0",
+    "microbundle-crl": "^0.13.10",
     "npm-run-all": "^4.1.5",
     "prettier": "^2.0.4",
     "react": "^16.13.1",
@@ -53,6 +53,8 @@
   "dependencies": {
     "@material-ui/core": "^4.11.2",
     "@material-ui/icons": "^4.11.2",
-    "create-react-library": "^3.1.1"
+    "@material-ui/lab": "^4.0.0-alpha.58",
+    "create-react-library": "^3.1.1",
+    "react-router-dom": "^5.2.0"
   }
 }

+ 0 - 4
src/CheckboxList/CheckboxList.js

@@ -1,4 +0,0 @@
-function CheckboxList() {
-    return (<div>checkbox list</div>);
-}
-export default CheckboxList;

+ 0 - 1
src/CheckboxList/index.js

@@ -1 +0,0 @@
-export { default } from '../CheckboxList'

+ 0 - 321
src/FieldList/FieldList.js

@@ -1,321 +0,0 @@
-import React, { useEffect, useRef } from 'react';
-import PropTypes from 'prop-types';
-import {
-    TextField,
-    Grid,
-    InputBase,
-    Button,
-    NativeSelect,
-    Box,
-    Typography
-} from '@material-ui/core';
-import { withStyles, makeStyles } from '@material-ui/core/styles';
-import SaveIcon from '@material-ui/icons/Save';
-import CancelIcon from '@material-ui/icons/Cancel';
-
-const BootstrapInput = withStyles((theme) => ({
-    root: {
-        'label + &': {
-            marginTop: theme.spacing(3),
-        },
-    },
-    input: {
-        borderRadius: 4,
-        position: 'relative',
-        backgroundColor: 'transparent',
-        border: '1px solid #ced4da',
-        fontSize: 16,
-        padding: '10px 26px 10px 12px',
-        transition: theme.transitions.create(['border-color', 'box-shadow']),
-        // Use the system font instead of the default Roboto font.
-        fontFamily: [
-            '-apple-system',
-            'BlinkMacSystemFont',
-            '"Segoe UI"',
-            'Roboto',
-            '"Helvetica Neue"',
-            'Arial',
-            'sans-serif',
-            '"Apple Color Emoji"',
-            '"Segoe UI Emoji"',
-            '"Segoe UI Symbol"',
-        ].join(','),
-        '&:focus': {
-            borderRadius: 4,
-            borderColor: '#80bdff',
-            boxShadow: '0 0 0 0.2rem rgba(0,123,255,.25)',
-        },
-    },
-}))(InputBase);
-
-const useStyles = makeStyles((theme) => ({
-    root: {
-        width: '100%',
-    },
-    paper: {
-        width: '100%',
-        marginBottom: theme.spacing(2),
-    },
-    table: {
-        minWidth: 750,
-    },
-    visuallyHidden: {
-        border: 0,
-        clip: 'rect(0 0 0 0)',
-        height: 1,
-        margin: -1,
-        overflow: 'hidden',
-        padding: 0,
-        position: 'absolute',
-        top: 20,
-        width: 1,
-    },
-    underline: {
-        "&&&:before": {
-            borderBottom: "none"
-        },
-        "&&:after": {
-            borderBottom: "none"
-        }
-    }
-}));
-
-function FieldList(props) {
-    const classes = useStyles();
-    const {
-        fields = [],
-        updateData = {},
-        onDataCallback
-    } = props;
-    const [data, setDataField] = React.useState(updateData != undefined ? updateData : {});
-    const [imgPreview, setImgPreviewPath] = React.useState(null);
-
-    const handleTextString = (e, fieldName) => {
-        setDataField({ ...data, [fieldName]: e.target.value });
-    }
-
-    const handleTextNumber = (e, fieldName) => {
-        setDataField({ ...data, [fieldName]: e.target.value });
-    }
-
-    const handleTextMultiline = (e, fieldName) => {
-        setDataField({ ...data, [fieldName]: e.target.value });
-    }
-
-    const handleDate = (e, fieldName) => {
-        setDataField({ ...data, [fieldName]: e.target.value });
-    }
-
-    const handleDropDownChange = (e, fieldName) => {
-        var selectedIndex = e.target.options.selectedIndex;
-        var selectedValue = e.target.options[selectedIndex].getAttribute('name');
-
-        var fn = fieldName.split('_');
-        var fieldId = fn[0] + '_' + 'id';
-        setDataField({ ...data, [fieldName]: selectedValue, [fieldId]: e.target.value });
-    }
-
-    const handleImgUpload = (e, fieldName) => {
-        e.preventDefault();
-        let reader = new FileReader();
-        let file = e.target.files[0];
-
-        reader.onloadend = () => {
-            setImgPreviewPath(reader.result);
-        }
-        reader.readAsDataURL(file);
-        setDataField({ ...data, [fieldName]: e.target.files[0].name });
-    }
-
-    const handleDataConfirm = () => {
-        onDataCallback(data);
-    }
-
-    return (
-        <div className={classes.root}>
-            <Grid container>
-                <Grid item xs={11}>
-                    {fields.map((f, i) => {
-
-                        if (f.type == 'text_string') {
-                            return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
-                                <Grid item xs={12} sm={5}>
-                                    <Box style={{ width: '150px' }}>
-                                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
-                                    </Box>
-                                </Grid>
-                                <Grid item xs={12} sm={7}>
-                                    <TextField id={f.fieldName}
-                                        variant="outlined"
-                                        autoComplete="off"
-                                        size={"small"}
-                                        style={{ width: '100%' }}
-                                        value={data != undefined ? data[f.fieldName] : null}
-                                        onChange={(e) => handleTextString(e, f.fieldName)}
-                                    />
-                                </Grid>
-                            </Grid>;
-                        }
-                        else if (f.type == 'text_number') {
-                            return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
-                                <Grid item xs={12} sm={5}>
-                                    <Box style={{ width: '150px' }}>
-                                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
-                                    </Box>
-                                </Grid>
-                                <Grid item xs={12} sm={7}>
-                                    <TextField
-                                        id={f.fieldName}
-                                        variant="outlined"
-                                        autoComplete="off"
-                                        size={"small"}
-                                        style={{ width: '100%' }}
-                                        type="number"
-                                        value={data != undefined ? data[f.fieldName] : ''}
-                                        // onChange={handleTextNumber}
-                                        onChange={(e) => handleTextNumber(e, f.fieldName)}
-                                    />
-                                </Grid>
-                            </Grid>;
-                        }
-                        else if (f.type == 'text_multiline') {
-                            return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
-                                <Grid item xs={12} sm={5}>
-                                    <Box style={{ width: '150px' }}>
-                                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
-                                    </Box>
-                                </Grid>
-                                <Grid item xs={12} sm={7}>
-                                    <TextField
-                                        id={f.fieldName}
-                                        multiline
-                                        autoComplete="off"
-                                        rows={3}
-                                        size={"small"}
-                                        style={{ width: '100%' }}
-                                        value={data != undefined ? data[f.fieldName] : ''}
-                                        variant="outlined"
-                                        onChange={(e) => handleTextMultiline(e, f.fieldName)}
-                                    />
-                                </Grid>
-                            </Grid>;
-                        }
-                        else if (f.type == 'date') {
-                            return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
-                                <Grid item xs={12} sm={5}>
-                                    <Box style={{ width: '150px' }}>
-                                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
-                                    </Box>
-                                </Grid>
-                                <Grid item xs={12} sm={7}>
-                                    <TextField
-                                        id={f.fieldName}
-                                        variant="outlined"
-                                        autoComplete="off"
-                                        size={"small"}
-                                        value={data != undefined ? data[f.fieldName] : ''}
-                                        type="date"
-                                        style={{ width: '100%' }}
-                                        // onChange={handleDate}
-                                        onChange={(e) => handleDate(e, f.fieldName)}
-                                    />
-                                </Grid>
-                            </Grid>;
-                        }
-                        else if (f.type == 'photo') {
-                            return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
-                                <Grid item xs={12} sm={5}>
-                                    <Box style={{ width: '150px' }}>
-                                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
-                                    </Box>
-                                </Grid>
-                                <Grid item xs={12} sm={7}>
-                                    <img src={imgPreview == null ? data['photo_url'] : imgPreview} style={{ width: '120px', height: '120px', border: '1px solid grey' }}></img>
-                                    <input type='file' id='img-upload' onChange={(e) => handleImgUpload(e, f.fieldName)}></input>
-                                </Grid>
-                            </Grid>;
-                        }
-                        else if (f.type == 'dropdown') {
-                            if (f.fieldName == 'priority') {
-
-                                return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
-                                    <Grid item xs={12} sm={5}>
-                                        <Box style={{ width: '150px' }}>
-                                            <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
-                                        </Box>
-                                    </Grid>
-                                    <Grid item xs={12} sm={7}>
-                                        <NativeSelect
-                                            id="demo-customized-select-native"
-                                            value={data != undefined ? data[f.fieldName] : ''}
-                                            onChange={(e) => handleDropDownChange(e, f.fieldName)}
-                                            id={f.fieldName}
-                                            input={<BootstrapInput />}
-                                            style={{ width: '100%' }}
-                                        >
-                                            <option aria-label="None" value="" >Select</option>
-                                            {f.options.map((d, i) => {
-                                                return <option name={d.name} value={d.id}>{d.name}</option>;
-                                            })}
-                                        </NativeSelect>
-                                    </Grid>
-                                </Grid>;
-                            } else {
-                                var fn = f.fieldName.split('_');
-                                var fieldId = fn[0] + '_' + 'id';
-
-                                return <Grid key={f.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
-                                    <Grid item xs={12} sm={5}>
-                                        <Box style={{ width: '150px' }}>
-                                            <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
-                                        </Box>
-                                    </Grid>
-                                    <Grid item xs={12} sm={7}>
-                                        <NativeSelect
-                                            id="demo-customized-select-native"
-                                            value={data != undefined ? data[fieldId] : ''}
-                                            onChange={(e) => handleDropDownChange(e, f.fieldName)}
-                                            id={f.fieldName}
-                                            input={<BootstrapInput />}
-                                            style={{ width: '100%' }}
-                                        >
-                                            <option aria-label="None" value="" >Select</option>
-                                            {f.options.map((d, i) => {
-                                                return <option name={d.name} value={d.id}>{d.name}</option>;
-                                            })}
-                                        </NativeSelect>
-                                    </Grid>
-                                </Grid>;
-                            }
-                        }
-                        else if (f.type == 'checkbox') {
-                            return <Grid></Grid>;
-                        }
-                        else if (f.type == 'radio') {
-                            return <Grid></Grid>;
-                        }
-                    })}
-
-                </Grid>
-                <Grid item xs={11}>
-                    <Box>
-                        <Button style={{ float: 'right' }}
-                            onClick={handleDataConfirm}
-                        > Confirm</Button>
-                    </Box>
-                </Grid>
-
-            </Grid>
-        </div>
-    );
-}
-
-FieldList.propTypes = {
-    history: PropTypes.object,
-    fields: PropTypes.array.isRequired,
-    updateData: PropTypes.object,
-    onDataCallback: PropTypes.func
-};
-
-export default (FieldList);
-

+ 54 - 0
src/MDropdown/MDropdown.js

@@ -0,0 +1,54 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+    Box,
+    Grid,
+    Typography,
+    NativeSelect
+} from '@material-ui/core';
+import { makeStyles } from '@material-ui/core/styles';
+
+const useStyles = makeStyles((theme) => ({
+    root: {
+        width: '100%',
+    },
+}));
+
+function MDropdown(props) {
+    const classes = useStyles();
+    const { field } = props;
+
+    return (
+        <div className={classes.root}>
+            <Grid key={field.fieldName} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                <Grid item xs={12} sm={5}>
+                    <Box style={{ width: '150px' }}>
+                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{field.label}</Typography>
+                    </Box>
+                </Grid>
+                <Grid item xs={12} sm={7}>
+                    <NativeSelect
+                        // value={data !== undefined ? data[fieldId] : ''}
+                        // onChange={(e) => handleDropDownChange(e, field.fieldName)}
+                        id={field.fieldName}
+                        // input={<BootstrapInput />}
+                        style={{ width: '100%' }}
+                    >
+                        <option aria-label="None" value="" >Select</option>
+                        {field.options.map((d, i) => {
+                            var name = d[field.fieldName] !== undefined ? d[field.fieldName] : d.name;
+                            return (<option name={name} value={d.id} key={d.id}>{name}</option>);
+                        })}
+                    </NativeSelect>
+                </Grid>
+            </Grid>
+        </div>
+    );
+}
+
+MDropdown.propTypes = {
+    history: PropTypes.object,
+    field: PropTypes.any,
+};
+
+export default (MDropdown);

+ 1 - 0
src/MDropdown/index.js

@@ -0,0 +1 @@
+export { default } from ".";

+ 535 - 0
src/MkForm/MkForm.js

@@ -0,0 +1,535 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+    TextField,
+    Grid,
+    InputBase,
+    Button,
+    NativeSelect,
+    Box,
+    Typography,
+    GridList,
+    GridListTile,
+    TableContainer,
+    Table,
+    TableHead,
+    TableRow,
+    TableBody,
+    TableCell,
+    Dialog,
+    DialogTitle,
+    DialogContent,
+} from '@material-ui/core';
+import AddIcon from '@material-ui/icons/Add';
+import { withStyles, makeStyles } from '@material-ui/core/styles';
+import Autocomplete, { createFilterOptions } from '@material-ui/lab/Autocomplete';
+
+const filter = createFilterOptions();
+
+const BootstrapInput = withStyles((theme) => ({
+    root: {
+        'label + &': {
+            marginTop: theme.spacing(3),
+        },
+    },
+    input: {
+        borderRadius: 4,
+        position: 'relative',
+        backgroundColor: 'transparent',
+        border: '1px solid #ced4da',
+        fontSize: 16,
+        padding: '10px 26px 10px 12px',
+        transition: theme.transitions.create(['border-color', 'box-shadow']),
+        // Use the system font instead of the default Roboto font.
+        fontFamily: [
+            '-apple-system',
+            'BlinkMacSystemFont',
+            '"Segoe UI"',
+            'Roboto',
+            '"Helvetica Neue"',
+            'Arial',
+            'sans-serif',
+            '"Apple Color Emoji"',
+            '"Segoe UI Emoji"',
+            '"Segoe UI Symbol"',
+        ].join(','),
+        '&:focus': {
+            borderRadius: 4,
+            borderColor: '#80bdff',
+            boxShadow: '0 0 0 0.2rem rgba(0,123,255,.25)',
+        },
+    },
+}))(InputBase);
+
+const useStyles = makeStyles((theme) => ({
+    root: {
+        width: '100%',
+    },
+    paper: {
+        width: '100%',
+        marginBottom: theme.spacing(2),
+    },
+    table: {
+        minWidth: 750,
+    },
+    visuallyHidden: {
+        border: 0,
+        clip: 'rect(0 0 0 0)',
+        height: 1,
+        margin: -1,
+        overflow: 'hidden',
+        padding: 0,
+        position: 'absolute',
+        top: 20,
+        width: 1,
+    },
+    underline: {
+        "&&&:before": {
+            borderBottom: "none"
+        },
+        "&&:after": {
+            borderBottom: "none"
+        }
+    }
+}));
+
+function MButton(props) {
+    const classes = useStyles();
+    const { action, onCallback } = props;
+
+    const handleAction = (e) => {
+        e.preventDefault();
+        onCallback(e);
+    }
+
+    return (
+        <div className={classes.root}>
+            <Box>
+                <Button
+                    variant="contained" style={{ float: 'right', margin: "5px" }}
+                    onClick={(e) => handleAction(e)}
+                >{action.icon}{action.label}</Button>
+            </Box>
+        </div>
+    );
+}
+
+MButton.propTypes = {
+    history: PropTypes.object,
+    action: PropTypes.object.isRequired,
+    onCallback: PropTypes.func.isRequired
+};
+
+
+
+function MkForm(props) {
+    const classes = useStyles();
+    const {
+        fields = [],
+        data = {},
+        onDropdownCreateNew,
+        actions = [],
+        partHeaders
+    } = props;
+    const [_data, setDataField] = React.useState(data !== undefined ? data : {});
+    const [open, setOpen] = React.useState(false);
+    // const [imgCollection, setImageCollection] = React.useState([]);
+    const [selectedPhoto, setSelectedPhoto] = React.useState("#");
+
+    const handleTextString = (e, fieldName) => {
+        setDataField({ ..._data, [fieldName]: e.target.value });
+    }
+
+    const handleTextNumber = (e, fieldName) => {
+        setDataField({ ..._data, [fieldName]: e.target.value });
+    }
+
+    const handleTextMultiline = (e, fieldName) => {
+        setDataField({ ..._data, [fieldName]: e.target.value });
+    }
+
+    const handleDate = (e, fieldName) => {
+        setDataField({ ..._data, [fieldName]: e.target.value });
+    }
+
+    const handleDropDownChange = (e, fieldName) => {
+        var selectedIndex = e.target.options.selectedIndex;
+        var selectedValue = e.target.options[selectedIndex].getAttribute('name');
+
+        var fn = fieldName.split('_');
+        var fieldId = fn[0] + '_' + 'id';
+        setDataField({ ..._data, [fieldName]: selectedValue, [fieldId]: e.target.value });
+    }
+
+    // const handleImgUpload = (e, fieldName) => {
+    //     e.preventDefault();
+    //     let reader = new FileReader();
+    //     let file = e.target.files[0];
+
+    //     reader.onloadend = () => {
+    //         setImgPreviewPath(reader.result);
+    //     }
+    //     reader.readAsDataURL(file);
+    //     setDataField({ ..._data, [fieldName]: e.target.files[0].name });
+    // }
+
+    const handleCanCreateNew = (data) => {
+        onDropdownCreateNew(data);
+    }
+
+    const onChangeValue = (fieldName, value) => {
+        setDataField({ ..._data, [fieldName]: value });
+    }
+
+    const onFileChange = (e, f) => {
+
+    }
+
+    const handleSelectItemDialog = () => {
+
+    }
+
+    return (
+        <div className={classes.root}>
+            <Grid container>
+                <Grid item xs={12}>
+                    {fields.map((f, i) => {
+
+                        if (f.type === 'text_string') {
+                            return <Grid key={f.field_name} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                <Grid item xs={12} sm={5}>
+                                    <Box style={{ width: '150px' }}>
+                                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
+                                    </Box>
+                                </Grid>
+                                <Grid item xs={12} sm={7}>
+                                    <TextField id={f.field_name}
+                                        variant="outlined"
+                                        autoComplete="off"
+                                        size="small"
+                                        style={{ width: '100%' }}
+                                        InputProps={{
+                                            readOnly: f.readOnly ? f.readOnly : false,
+                                        }}
+                                        value={_data !== undefined ? _data[f.field_name] : ''}
+                                        onChange={(e) => handleTextString(e, f.field_name)}
+                                    />
+                                </Grid>
+                            </Grid>;
+                        }
+                        else if (f.type === 'text_number') {
+                            return <Grid key={f.field_name} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                <Grid item xs={12} sm={5}>
+                                    <Box style={{ width: '150px' }}>
+                                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
+                                    </Box>
+                                </Grid>
+                                <Grid item xs={12} sm={7}>
+                                    <TextField
+                                        id={f.field_name}
+                                        variant="outlined"
+                                        autoComplete="off"
+                                        size="small"
+                                        style={{ width: '100%' }}
+                                        type="number"
+                                        value={_data !== undefined ? _data[f.field_name] : ''}
+                                        onChange={(e) => handleTextNumber(e, f.field_name)}
+                                    />
+                                </Grid>
+                            </Grid>;
+                        }
+                        else if (f.type === 'text_multiline') {
+                            return <Grid key={f.field_name} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                <Grid item xs={12} sm={5}>
+                                    <Box style={{ width: '150px' }}>
+                                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
+                                    </Box>
+                                </Grid>
+                                <Grid item xs={12} sm={7}>
+                                    <TextField
+                                        id={f.field_name}
+                                        multiline
+                                        autoComplete="off"
+                                        rows={3}
+                                        size="small"
+                                        style={{ width: '100%' }}
+                                        value={_data !== undefined ? _data[f.field_name] : ''}
+                                        variant="outlined"
+                                        onChange={(e) => handleTextMultiline(e, f.field_name)}
+                                    />
+                                </Grid>
+                            </Grid>;
+                        }
+                        else if (f.type === 'date') {
+                            return <Grid key={f.field_name} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                <Grid item xs={12} sm={5}>
+                                    <Box style={{ width: '150px' }}>
+                                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
+                                    </Box>
+                                </Grid>
+                                <Grid item xs={12} sm={7}>
+                                    <TextField
+                                        id={f.field_name}
+                                        variant="outlined"
+                                        autoComplete="off"
+                                        size="small"
+                                        value={_data !== undefined ? _data[f.field_name] : ''}
+                                        type="date"
+                                        style={{ width: '100%' }}
+                                        onChange={(e) => handleDate(e, f.field_name)}
+                                    />
+                                </Grid>
+                            </Grid>;
+                        }
+                        else if (f.type === 'dropdown') {
+                            if (f.options !== undefined && f.option_label_field !== undefined) {
+                                if (f.field_name === 'priority') {
+
+                                    return <Grid key={f.field_name} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                        <Grid item xs={12} sm={5}>
+                                            <Box style={{ width: '150px' }}>
+                                                <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
+                                            </Box>
+                                        </Grid>
+                                        <Grid item xs={12} sm={7}>
+                                            <NativeSelect
+                                                value={_data !== undefined ? _data[f.field_name] : ''}
+                                                onChange={(e) => handleDropDownChange(e, f.field_name)}
+                                                id={f.field_name}
+                                                input={<BootstrapInput />}
+                                                style={{ width: '100%' }}
+                                            >
+                                                <option aria-label="None" value="" >Select</option>
+                                                {f.options.map((d, i) => {
+                                                    return (<option name={d.name} value={d.id} key={d.id}>{d.name}</option>);
+                                                })}
+                                            </NativeSelect>
+                                        </Grid>
+                                    </Grid>;
+                                } else {
+                                    return <Grid key={f.field_name} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                        <Grid item xs={12} sm={5}>
+                                            <Box style={{ width: '150px' }}>
+                                                <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
+                                            </Box>
+                                        </Grid>
+                                        <Grid item xs={12} sm={7}>
+                                            <Autocomplete
+                                                id="combo-box-demo"
+                                                options={f.options}
+                                                getOptionLabel={(option) => {
+                                                    if (typeof option === 'string') {
+                                                        return option;
+                                                    }
+                                                    return option[f.option_label_field];
+                                                }}
+                                                style={{ width: '100%' }}
+                                                size='small'
+                                                value={_data !== undefined ? _data[f.field_name] ? _data[f.field_name] : " " : " "}
+                                                filterOptions={(options, params) => {
+                                                    console.log("Autocomplete", f.can_create);
+                                                    if (f.can_create) {
+                                                        var newFilter = ['+ Add New']
+                                                        var filtered = filter(options, params);
+                                                        return [...newFilter, ...filtered];
+                                                    } else {
+                                                        var _filtered = filter(options, params);
+                                                        return _filtered;
+                                                    }
+                                                }}
+                                                onChange={(event, newValue) => {
+                                                    if (typeof newValue === 'string') {
+                                                        console.log('f.field_name', f.field_name, " f.can_create", f.can_create);
+                                                        var d = {
+                                                            "canCreate": f.can_create,
+                                                            "fields": f.fields,
+                                                            "name": f.name,
+                                                            "fieldName": f.field_name
+                                                        }
+                                                        handleCanCreateNew(d);
+                                                    } else {
+                                                        if (newValue != null && newValue.inputValue !== '' && newValue.product_desc !== "") {
+                                                            onChangeValue(f.field_name, newValue[f.option_label_field]);
+                                                        }
+                                                    }
+                                                }}
+                                                renderInput={(params) => <TextField {...params} variant="outlined" />}
+
+                                            />
+
+                                        </Grid>
+                                    </Grid>;
+                                }
+                            }
+                        }
+                        else if (f.type === 'photo_list') {
+                            console.log('photo_list:', _data);
+                            return <div>
+                                <Grid
+                                    key={f.field_name} container
+                                    style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                    <Grid item xs={12} sm={5}>
+                                        <Box style={{ width: '150px' }}>
+                                            <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
+                                        </Box>
+                                    </Grid>
+                                    <Grid item xs={12} sm={7}>
+                                        <div style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                            <form>
+                                                <div className="form-group">
+                                                    <input type="file" name="imgCollection"
+                                                        onChange={(e) => onFileChange(e, f.field_name)}
+                                                        multiple />
+                                                </div>
+                                            </form>
+                                        </div>
+                                    </Grid>
+                                </Grid>
+                                {_data[f.field_name] !== undefined && _data[f.field_name].length !== 0 ?
+                                    <Grid
+                                        key={f.field_name} container
+                                        style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                        <Grid item xs={12}>
+                                            <div style={{ display: 'block', alignItems: 'center', marginBottom: '10px' }}>
+                                                <GridList className={classes.gridList}>
+                                                    {_data[f.field_name] === undefined ? <span /> : _data[f.field_name].map((tile) => (
+                                                        <GridListTile key={tile} style={{ width: '100px', height: '100px' }}>
+                                                            <img src={tile} alt={tile} onClick={(e) => {
+                                                                // setSelectedPhoto(tile);
+                                                                setOpen(true);
+                                                            }
+                                                            } />
+                                                        </GridListTile>
+                                                    ))}
+                                                </GridList>
+                                            </div>
+                                        </Grid>
+                                        <Dialog maxWidth="lg" aria-labelledby="customized-dialog-title" open={open}>
+                                            <DialogTitle id="customized-dialog-title" onClose={(e) => setOpen(false)} >
+                                                Photos
+                                            </DialogTitle>
+                                            <DialogContent dividers>
+                                                <Grid item xs={12}>
+                                                    <Grid>
+                                                        <img src={selectedPhoto} className="show-img" alt="logo" />
+                                                    </Grid>
+                                                    <br />
+                                                    <Grid container spacing={3}>
+                                                        {_data[f.field_name].length > 0 ? _data[f.field_name].map((value) => (
+                                                            <Grid key={value} item>
+                                                                <Box className="square" > <img src={value} className="thumnail-img" alt="logo" onClick={(e) => setSelectedPhoto(value)} /></Box>
+                                                            </Grid>
+                                                        )) : <span />}
+                                                    </Grid>
+                                                </Grid>
+                                            </DialogContent>
+                                        </Dialog>
+                                    </Grid>
+                                    : <Grid />}
+                            </div>;
+                        }
+                        else if (f.type === 'list') {
+                            console.log('list', _data[f.field_name]);
+                            return <div>
+                                <Grid
+                                    key={f.field_name} container
+                                    style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                    <Grid item xs={12} sm={5}>
+                                        <Box style={{ width: '150px' }}>
+                                            <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
+                                        </Box>
+                                    </Grid>
+                                    <Grid item xs={12} sm={7}>
+                                        <div style={{ display: 'block', alignItems: 'center', marginBottom: '10px' }}>
+                                            <Box>
+                                                <Button onClick={handleSelectItemDialog}><AddIcon /></Button>
+                                            </Box>
+                                        </div>
+                                    </Grid>
+                                </Grid>
+                                <Grid
+                                    key={f.field_name} container
+                                    style={{ display: 'block', alignItems: 'center', marginBottom: '10px' }}>
+
+                                    <div style={{ display: 'block', alignItems: 'center', marginBottom: '10px' }}>
+                                        <TableContainer>
+                                            <Table className={classes.table} size="small" aria-label="a dense table">
+                                                <TableHead>
+                                                    <TableRow>
+                                                        {partHeaders.map((h, i) => {
+                                                            return (<TableCell key={h.id} align='left'>{h.label}</TableCell>);
+                                                        })}
+                                                    </TableRow>
+                                                </TableHead>
+                                                <TableBody>
+                                                    {_data[f.field_name].length > 0 ? _data[f.field_name].map((row) => (
+                                                        <TableRow key={row.name}>
+                                                            {partHeaders.map((h, i) => {
+                                                                return (<TableCell key={h.id} align={h.numeric ? 'right' : 'left'}>{row[h.id]}</TableCell>);
+                                                            })}
+                                                        </TableRow>
+                                                    )) : <span />
+                                                    }
+                                                </TableBody>
+                                            </Table>
+                                        </TableContainer>
+                                    </div>
+
+                                </Grid>
+                            </div>;
+                        }
+                        else if (f.type === 'time') {
+                            return <Grid key={f.field_name} container style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
+                                <Grid item xs={12} sm={5}>
+                                    <Box style={{ width: '150px' }}>
+                                        <Typography style={{ paddingRight: '30px', color: 'grey' }}>{f.label}</Typography>
+                                    </Box>
+                                </Grid>
+                                <Grid item xs={12} sm={7}> <TextField
+                                    id="time"
+                                    variant="outlined"
+                                    size="small"
+                                    type="time"
+                                    className={classes.textField}
+                                    InputLabelProps={{
+                                        shrink: true,
+                                    }}
+                                    inputProps={{
+                                        step: 300, // 5 min
+                                    }}
+                                // onChange={(e) => handleTime(e, f.field_name)}
+                                />
+                                </Grid>
+                            </Grid>;
+                        }
+                    })}
+
+                </Grid>
+
+                {/* display actions buttons */}
+                {actions.length > 0 ?
+                    <Grid item xs={12}>
+                        {actions.map((a) => {
+                            if (a.status === _data.status) {
+                                return <MButton action={a} onCallback={(event) => a.callback(event, _data)} />;
+                            }
+                        })}
+
+                    </Grid> : <Grid />}
+            </Grid>
+        </div>
+
+    );
+}
+
+MkForm.propTypes = {
+    history: PropTypes.object,
+    fields: PropTypes.array.isRequired,
+    data: PropTypes.object,
+    isNew: PropTypes.bool,
+    actions: PropTypes.array,
+    onDropdownCreateNew: PropTypes.func
+};
+
+export default (MkForm);
+

+ 0 - 0
src/FieldList/index.js → src/MkForm/index.js


+ 41 - 44
src/InfoPage/InfoPage.js → src/MkInfo/MkInfo.js

@@ -2,7 +2,6 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { makeStyles } from '@material-ui/core/styles';
 import { Grid, Box, Typography, Button } from '@material-ui/core';
-import { FieldList } from '..';
 
 const useStyles = makeStyles((theme) => ({
     root: {
@@ -35,7 +34,6 @@ const useStyles = makeStyles((theme) => ({
         }
     }, button: {
         color: 'white',
-        color: theme.palette.primary.main,
         width: 150,
         height: 55
     },
@@ -51,11 +49,6 @@ const useStyles = makeStyles((theme) => ({
         color: theme.palette.primary.main,
         fontWeight: "bold"
     },
-    paper: {
-        padding: theme.spacing(2),
-        textAlign: 'center',
-        color: theme.palette.text.secondary,
-    },
 }));
 
 function getDataString(data, fieldName) {
@@ -63,7 +56,7 @@ function getDataString(data, fieldName) {
 }
 
 
-function InfoPage(props) {
+function MkInfo(props) {
     const classes = useStyles();
     const {
         infoData,
@@ -73,17 +66,17 @@ function InfoPage(props) {
         currentTabName,
         actions } = props;
 
-    const [editable, setEditable] = React.useState(isEditable != undefined ? isEditable : true);
-    const [data, setData] = React.useState({});
+    const [editable, setEditable] = React.useState(isEditable !== undefined ? isEditable : true);
+    // const [data, setData] = React.useState({});
 
     const handleEdit = () => {
         setEditable(false)
     }
 
-    const handleUpdateData = (data) => {
-        console.log('handle update date:', data);
-        setData(data);
-    }
+    // const handleUpdateData = (data) => {
+    //     console.log('handle update date:', data);
+    //     setData(data);
+    // }
 
 
     return (
@@ -91,25 +84,26 @@ function InfoPage(props) {
             {isNew ?
                 <Grid container style={{ marginTop: '30px' }}>
                     <Grid item xs={12} sm={7}>
-                        <FieldList
+                        {/* <MkForm
                             updateData={infoData}
                             fields={displayFields}
                             isNew={isNew}
                             onDataCallback={(d) => handleUpdateData(d)}
-                        ></FieldList>
+                        ></MkForm> */}
                     </Grid>
                 </Grid> : <Grid container style={{ marginTop: '30px' }}>
                     <Grid item xs={12} sm={7}>
                         {!editable ?
-                            <FieldList
-                                fields={displayFields}
-                                isNew={isNew}
-                                updateData={infoData}
-                                onDataCallback={(d) => handleUpdateData(d)}
-                            ></FieldList>
+                            // <MkForm
+                            //     fields={displayFields}
+                            //     isNew={isNew}
+                            //     updateData={infoData}
+                            //     onDataCallback={(d) => handleUpdateData(d)}
+                            // ></MkForm>
+                            <div/>
                             :
                             displayFields.map((d, i) => {
-                                return <Grid container>
+                                return (<Grid container key={i}>
                                     <Grid item xs={12} style={{ display: 'flex', alignItems: 'center', marginBottom: '10px' }}>
                                         <Grid item xs={12} sm={5}>
                                             <Box style={{ width: '250px' }}>
@@ -117,11 +111,14 @@ function InfoPage(props) {
                                             </Box>
                                         </Grid>
                                         <Grid item xs={12} sm={7}>
-                                            {d.type == 'photo' ? <img src={infoData['photo_url']} style={{ width: '120px', height: '120px', border: '1px solid grey' }}></img> :
-                                                <Typography style={{ paddingRight: '30px' }}>{infoData != undefined ? getDataString(infoData, d.fieldName) : ''}</Typography>}
+                                            {d.type === 'photo' ? 
+                                            <img/>
+                                            // <img src={infoData['photo_url']} style={{ width: '120px', height: '120px', border: '1px solid grey' }}></img>
+                                             :
+                                                <Typography style={{ paddingRight: '30px' }}>{infoData !== undefined ? getDataString(infoData, d.fieldName) : ''}</Typography>}
                                         </Grid>
                                     </Grid>
-                                </Grid>;
+                                </Grid>);
                             })}
                     </Grid>
                     <Grid item xs={12} sm={7}>
@@ -132,29 +129,29 @@ function InfoPage(props) {
 
                             {actions.map((a, i) => {
 
-                                if (currentTabName == 'account') {
-                                    if (infoData.status == 'invited') {
+                                if (currentTabName === 'account') {
+                                    if (infoData.status === 'invited') {
                                         return <Box>
                                             <Button style={{ color: 'white', backgroundColor: 'grey', float: 'right', marginLeft: '10px' }}
-                                                onClick={() => a.callback(data)}
+                                                // onClick={() => a.callback(data)}
                                             >{a.label}</Button>
                                         </Box>;
                                     }
-                                    if (infoData.status == 'joined') {
+                                    if (infoData.status === 'joined') {
                                         return <Box>
                                             <Button style={{ color: 'white', backgroundColor: 'grey', float: 'right', marginLeft: '10px' }}
-                                                onClick={() => a.callback(data)}
+                                                // onClick={() => a.callback(data)}
                                             >{a.label}</Button>
                                         </Box>;
                                     }
-                                    if (infoData.status == 'disabled') {
+                                    if (infoData.status === 'disabled') {
                                         return <Box>
                                             <Button style={{ color: 'white', backgroundColor: 'grey', float: 'right', marginLeft: '10px' }}
-                                                onClick={() => a.callback(data)}
+                                                // onClick={() => a.callback(data)}
                                             >{a.label}</Button>
                                         </Box>;
                                     }
-                                    if (infoData.status == 'requested') {
+                                    if (infoData.status === 'requested') {
                                         if (editable) {
                                             return <Box>
                                                 <Button style={{ marginLeft: '10px' }}
@@ -164,7 +161,7 @@ function InfoPage(props) {
                                         } else {
                                             return <Box>
                                                 <Button style={{ color: 'white', backgroundColor: 'grey', float: 'right', marginLeft: '10px' }}
-                                                    onClick={() => a.callback(data)}
+                                                    // onClick={() => a.callback(data)}
                                                 >{a.label}</Button>
                                             </Box>;
                                         }
@@ -172,7 +169,7 @@ function InfoPage(props) {
                                     }
                                 } else {
                                     if (editable) {
-                                        if (a.action_type == 'edit') {
+                                        if (a.action_type === 'edit') {
                                             console.log('type: ', a.action_type, 'editable: ', editable);
 
                                             return <Box>
@@ -181,25 +178,25 @@ function InfoPage(props) {
                                                 >{a.icon}{a.label}</Button>
                                             </Box>
                                         }
-                                        if (a.action_type == 'delete') {
+                                        if (a.action_type === 'delete') {
                                             return <Box>
                                                 <Button style={{ float: 'right', marginLeft: '10px' }}
-                                                    onClick={() => a.callback(data)}
+                                                    // onClick={() => a.callback(data)}
                                                 >{a.icon}{a.label}</Button>
                                             </Box>
                                         }
                                     } else {
-                                        if (a.action_type == 'save') {
+                                        if (a.action_type === 'save') {
                                             return <Box>
                                                 <Button style={{ marginLeft: '10px' }}
-                                                    onClick={() => a.callback(data)}
+                                                    // onClick={() => a.callback(data)}
                                                 >{a.icon}{a.label}</Button>
                                             </Box>
                                         }
-                                        if (a.action_type == 'cancel') {
+                                        if (a.action_type === 'cancel') {
                                             return <Box>
                                                 <Button style={{ float: 'right', marginLeft: '10px' }}
-                                                    onClick={() => a.callback(data)}
+                                                    // onClick={() => a.callback(data)}
                                                 >{a.icon}{a.label}</Button>
                                             </Box>
                                         }
@@ -215,7 +212,7 @@ function InfoPage(props) {
     );
 }
 
-InfoPage.propTypes = {
+MkInfo.propTypes = {
     history: PropTypes.object,
     infoData: PropTypes.object,
     displayFields: PropTypes.array,
@@ -224,4 +221,4 @@ InfoPage.propTypes = {
     actions: PropTypes.any
 };
 
-export default (InfoPage);
+export default (MkInfo);

+ 0 - 0
src/InfoPage/index.js → src/MkInfo/index.js


+ 535 - 0
src/MkTable/MkTable.js

@@ -0,0 +1,535 @@
+import React, { useEffect } from 'react';
+import PropTypes from 'prop-types';
+import Table from '@material-ui/core/Table';
+import TableBody from '@material-ui/core/TableBody';
+import TableCell from '@material-ui/core/TableCell';
+import TableContainer from '@material-ui/core/TableContainer';
+import TableHead from '@material-ui/core/TableHead';
+import TablePagination from '@material-ui/core/TablePagination';
+import TableRow from '@material-ui/core/TableRow';
+import TableSortLabel from '@material-ui/core/TableSortLabel';
+import Typography from '@material-ui/core/Typography';
+import EditIcon from '@material-ui/icons/Edit';
+import ExpandMore from '@material-ui/icons/ExpandMore';
+import { Box, Button, Dialog, DialogActions, DialogTitle, Grid, IconButton, Menu, MenuItem } from '@material-ui/core';
+import CircularProgress from '@material-ui/core/CircularProgress';
+import { withStyles, makeStyles } from '@material-ui/core/styles';
+
+function descendingComparator(a, b, _orderBy) {
+    if (b[_orderBy] < a[_orderBy]) {
+        return -1;
+    }
+    if (b[_orderBy] > a[_orderBy]) {
+        return 1;
+    }
+    return 0;
+}
+
+function getComparator(_order, _orderBy) {
+    return _order === 'desc'
+        ? (a, b) => descendingComparator(a, b, _orderBy)
+        : (a, b) => -descendingComparator(a, b, _orderBy);
+}
+
+function stableSort(array, comparator) {
+    const stabilizedThis = array.map((el, index) => [el, index]);
+    stabilizedThis.sort((a, b) => {
+        const _order = comparator(a[0], b[0]);
+        if (_order !== 0) return _order;
+        return a[1] - b[1];
+    });
+    return stabilizedThis.map((el) => el[0]);
+}
+
+const StyledTableCell = withStyles((theme) => ({
+    head: {
+        backgroundColor: '#0d47a1a8',
+        color: theme.palette.common.white,
+    },
+    body: {
+        fontSize: 14,
+    },
+}))(TableCell);
+
+
+function EnhancedTableHead(props) {
+    const { classes, _order, _orderBy, onRequestSort, headCells } = props;
+    const createSortHandler = (property) => (event) => {
+        onRequestSort(event, property);
+        // onGetData();
+    };
+
+    return (
+        <TableHead>
+            <TableRow>
+                {headCells.map((headCell) => (
+                    <StyledTableCell
+                        key={headCell.id}
+                        align={headCell.numeric ? 'right' : 'left'}
+                        padding={headCell.disablePadding ? 'none' : 'default'}
+                        sortDirection={_orderBy === headCell.id ? _order : false}
+                        style={{ width: headCell.id === 'sr' ? '15px' : headCell.width ? headCell.width : '' }}
+                    >
+                        {headCell.id !== 'sr' ?
+                            <TableSortLabel
+                                active={_orderBy === headCell.id}
+                                direction={_orderBy === headCell.id ? _order : 'asc'}
+                                onClick={createSortHandler(headCell.id)}
+                                style={{ whiteSpace: "nowrap" }}
+                            >
+                                {headCell.label}
+                                {_orderBy === headCell.id ? (
+                                    <span className={classes.visuallyHidden}>
+                                        {_order === 'desc' ? 'sorted descending' : 'sorted ascending'}
+                                    </span>
+                                ) : null}
+                            </TableSortLabel>
+                            : <TableSortLabel
+                                hideSortIcon="true"
+                                align="right"
+                            >
+                                {headCell.label}
+
+                            </TableSortLabel>
+                        }
+
+                    </StyledTableCell>
+                ))}
+                <StyledTableCell style={{ width: '100px' }} />
+
+            </TableRow>
+        </TableHead>
+    );
+}
+
+EnhancedTableHead.propTypes = {
+    classes: PropTypes.object.isRequired,
+    onRequestSort: PropTypes.func.isRequired,
+    onSelectAllClick: PropTypes.func.isRequired,
+    _order: PropTypes.oneOf(['asc', 'desc']).isRequired,
+    _orderBy: PropTypes.string.isRequired,
+    rowCount: PropTypes.number.isRequired,
+};
+
+const useStyles = makeStyles((theme) => ({
+    root: {
+        width: '100%',
+    },
+    paper: {
+        width: '100%',
+        marginBottom: theme.spacing(2),
+    },
+    table: {
+        // minWidth: 750,
+        tableLayout: 'fixed'
+    },
+    visuallyHidden: {
+        b_order: 0,
+        clip: 'rect(0 0 0 0)',
+        height: 1,
+        margin: -1,
+        overflow: 'hidden',
+        padding: 0,
+        position: 'absolute',
+        top: 20,
+        width: 1,
+    },
+    underline: {
+        "&&&:before": {
+            b_orderBottom: "none"
+        },
+        "&&:after": {
+            b_orderBottom: "none"
+        }
+    },
+    bomLink: {
+        cursor: "pointer",
+        color: theme.primary,
+        textDecoration: "underline",
+    }
+}));
+
+const StyledTableRow = withStyles((theme) => ({
+    root: {
+        '&:nth-of-type(even)': {
+            backgroundColor: '#0d47a11c',
+        },
+    },
+}))(TableRow);
+
+function getUpdatedDate(p) {
+    var statusDate = p.updated_date;
+    var day = '';
+    if (statusDate !== undefined) {
+        var convertDate = new Date(statusDate.toDate());
+        var dd = String(convertDate.getDate()).padStart(2, '0');
+        var mm = String(convertDate.getMonth() + 1).padStart(2, '0');
+        var yyyy = convertDate.getFullYear();
+
+        day = mm + '/' + dd + '/' + yyyy;
+    }
+
+    return day.toString();
+}
+
+export const formatDateToLocal = (date, withTime = true) => {
+    if (!date) return "";
+    var d = new Date(date);
+    var ampm = d.getHours() >= 12 ? 'PM' : 'AM';
+    var hours = d.getHours() > 12 ? d.getHours() - 12 : d.getHours();
+    if (withTime) {
+        return ("0" + (d.getMonth() + 1)).slice(-2) + "/" + ("0"
+            + d.getDate()).slice(-2) + "/" + d.getFullYear()
+            + " " + ("0" + (hours)).slice(-2)
+            + ":" + ("0" + (d.getMinutes())).slice(-2)
+            + ":" + ("0" + (d.getSeconds())).slice(-2)
+            + " " + ampm;
+    } else {
+        return ("0" + (d.getMonth() + 1)).slice(-2) + "/" + ("0"
+            + d.getDate()).slice(-2) + "/" + d.getFullYear();
+    }
+}
+
+function RowMenu(props) {
+    const { row, actions, onSelectedAction, onRowEdit } = props;
+    const [anchorEl, setAnchorEl] = React.useState(null);
+
+    const handleMenuClick = (event) => {
+        event.stopPropagation();
+        setAnchorEl(event.currentTarget);
+    };
+
+    const handleSelectMenu = (e, row, action) => {
+        e.stopPropagation();
+        onSelectedAction(row, action.action_name);
+        setAnchorEl(null);
+    }
+
+    const handleClose = (e) => {
+        setAnchorEl(null);
+        e.stopPropagation();
+    };
+
+    const handleEdit = (e) => {
+        onRowEdit(row);
+        e.stopPropagation();
+    }
+
+    return (
+        <div>
+            <Menu
+                id={`actions-${row.id}`}
+                anchorEl={anchorEl}
+                keepMounted
+                open={Boolean(anchorEl)}
+                onClose={handleClose}
+            >
+                {actions.map((action) => {
+                    return <MenuItem key={action.display_name}
+                        onClick={(e) => handleSelectMenu(e, row, action)}
+                    >
+                        {action.display_name}
+                    </MenuItem>
+                }
+                )}
+            </Menu>
+            <Grid
+                container
+                direction="row"
+                justify="flex-end"
+                alignItems="center"
+                style={{ display: 'flex' }}>
+                <IconButton
+                    id={`edit-${row.id}`}
+                    aria-label="more"
+                    aria-controls="long-menu"
+                    aria-haspopup="true"
+                    onClick={handleEdit}
+                    size="small"
+                >
+                    <EditIcon />
+                </IconButton>
+                <Box style={{ width: '10px' }} />
+                <IconButton
+                    id={`dropdown-${row.id}`}
+                    aria-label="more"
+                    aria-controls="long-menu"
+                    aria-haspopup="true"
+                    size="small"
+                    onClick={handleMenuClick}
+                >
+                    <ExpandMore />
+                </IconButton>
+            </Grid>
+
+        </div>
+    );
+}
+
+RowMenu.propTypes = {
+    row: PropTypes.object.isRequired,
+    actions: PropTypes.array.isRequired,
+    onSelectedAction: PropTypes.func.isRequired,
+    onRowEdit: PropTypes.func
+}
+
+function ConfirmDialog(props) {
+    const { type, itemName, openDialog, onCancel, onContinue } = props;
+    const [open, setOpen] = React.useState(openDialog);
+
+    const handleClose = () => {
+        setOpen(false);
+        onCancel(false);
+    };
+
+    const handleContinue = () => {
+        onContinue(true);
+    }
+
+    return (
+        <div>
+            <Dialog
+                open={open}
+                onClose={handleClose}
+                aria-labelledby="alert-dialog-title"
+                aria-describedby="alert-dialog-description"
+            >
+                <DialogTitle id="alert-dialog-title">{"Delete this " + type + ' "' + itemName + '"?'}</DialogTitle>
+
+                <DialogActions>
+                    <Button onClick={handleClose} color="primary">
+                        Cancel
+                    </Button>
+                    <Button onClick={handleContinue} color="primary" autoFocus>
+                        Delete
+                    </Button>
+                </DialogActions>
+            </Dialog>
+        </div>
+    );
+}
+
+ConfirmDialog.propTypes = {
+    history: PropTypes.object,
+    type: PropTypes.string,
+    itemName: PropTypes.string,
+    openDialog: PropTypes.bool,
+    onCancel: PropTypes.func,
+    onContinue: PropTypes.func
+};
+
+function MkTable(props) {
+    const classes = useStyles();
+    const { dispatch,
+        data = [],
+        headers = [],
+        actions,
+        onActions, title,
+        page,
+        rowsPerPage,
+        noMoreToLoad = false,
+        order,
+        orderBy,
+        isLoading = false,
+        onChangePaginatePage,
+        onGetData,
+        onUpdateDataRow,
+        onChangeRowPerPage,
+        dense = true
+    } = props;
+
+    const [_rowsPerPage, setRowsPerPage] = React.useState(rowsPerPage);
+    const [_page, setPage] = React.useState(page);
+    const [_noMoreToLoad, setNoMoreToLoad] = React.useState(noMoreToLoad);
+    const [_order, setOrder] = React.useState(order);
+    const [_orderBy, setOrderBy] = React.useState(orderBy);
+    const [_isLoading, setIsLoading] = React.useState(isLoading);
+    const [_isConfirm, setIsConfirm] = React.useState(false);
+    const [itemName, setItemName] = React.useState('');
+    const [row, setRow] = React.useState({});
+    const [action, setAction] = React.useState('');
+    const [_dense, setDense] = React.useState(dense);
+
+    const handleSelectMenu = (row, action) => {
+        if (action === 'delete') {
+            setItemName(row.name === undefined ? row.product_desc : row.name);
+            setIsConfirm(true);
+            setRow(row);
+            setAction(action);
+        } else {
+            onActions(row, action);
+        }
+    }
+
+    const handleDelete = (v) => {
+        setIsConfirm(false);
+        onActions(row, action);
+    }
+
+    const handleCancel = (v) => {
+        setIsConfirm(false);
+    }
+
+    const handleRowEdit = (row) => {
+        onUpdateDataRow(row);
+    }
+
+    var offset = _page * _rowsPerPage;
+
+    useEffect(() => {
+        setNoMoreToLoad(noMoreToLoad);
+        setPage(page);
+        setOrder(order);
+        setOrderBy(orderBy);
+        setIsLoading(isLoading);
+        setRowsPerPage(rowsPerPage);
+        setDense(dense);
+    }, []);
+
+    const handleRequestSort = (event, property) => {
+        const isAsc = _orderBy === property && _order === 'asc';
+        setOrder(isAsc ? 'desc' : 'asc');
+        setOrderBy(property);
+    };
+
+    const handleChangePage = (event, newPage) => {
+        if (!_noMoreToLoad && (newPage + 1) * _rowsPerPage >= data.length) {
+            onGetData();
+        }
+        setPage(newPage);
+        onChangePaginatePage(newPage);
+    };
+
+    const handleChangeRowsPerPage = (event) => {
+        setRowsPerPage(parseInt(event.target.value));
+        onChangeRowPerPage(parseInt(event.target.value));
+    };
+
+    const getStatus = (data, header) => {
+        var v = data[header.id];
+        var _color = 'red';
+        if (v === 'Pending') {
+            _color = 'red';
+        } else if (v === 'Started') {
+            _color = 'orange';
+        } else {
+            _color = 'green';
+        }
+        return (<TableCell key={header.id} align={header.numeric ? 'right' : 'left'} ><Typography style={{ color: _color, fontWeight: '500' }}>{data[header.id]}</Typography></TableCell>);
+    };
+
+    return (
+
+        <div className={classes.root}>
+            <Grid container>
+                <Grid item>
+                    <TableContainer>
+                        <Table
+                            className={classes.table}
+                            aria-labelledby="tableTitle"
+                            size={_dense ? 'small' : 'medium'}
+                            aria-label="enhanced table"
+                        >
+                            <EnhancedTableHead
+                                classes={classes}
+                                headCells={headers}
+                                _order={_order}
+                                _orderBy={_orderBy}
+                                onRequestSort={handleRequestSort}
+                                rowCount={data.length !== undefined ? data.length : 0}
+                                dispatch={dispatch}
+                            />
+
+                            <TableBody>
+                                {_isLoading ? <StyledTableRow >
+                                    <TableCell colSpan={headers.length} align="center"> <CircularProgress /></TableCell>
+                                </StyledTableRow> :
+                                    (data.length !== 0 ? stableSort(data, getComparator(_order, _orderBy))
+                                        .slice(_page * _rowsPerPage, _page * _rowsPerPage + _rowsPerPage)
+                                        .map((row, index) => {
+                                            return (
+                                                <StyledTableRow
+                                                    hover
+                                                    role="checkbox"
+                                                    tabIndex={-1}
+                                                    key={row.id}
+                                                    id={row.id}
+                                                >
+
+                                                    {headers.map((h, i) => {
+                                                        if (h.id === 'sr') {
+                                                            return (<TableCell key={h.id} align="right" style={{ width: '15px' }}>{++offset}</TableCell>);
+                                                        }
+                                                        if (h.id === 'status') {
+                                                            getStatus(row, h);
+                                                            return (<TableCell key={h.id} align={h.numeric ? 'right' : 'left'}>{row[h.id]}</TableCell>);
+                                                        }
+                                                        if (h.id === 'updated_date') {
+                                                            return (<TableCell key={h.id} align={h.numeric ? 'right' : 'left'} style={{ width: h.width ? h.width : null }}>{getUpdatedDate(row)}</TableCell>);
+                                                        } else {
+                                                            return (<TableCell key={h.id} align={h.numeric ? 'right' : 'left'} style={{ width: h.width ? h.width : null }}
+                                                            >{row[h.id]}</TableCell>);
+                                                        }
+                                                    })}
+                                                    {actions ?
+                                                        <TableCell style={{ width: '150px' }} align='right'>
+                                                            <RowMenu
+                                                                actions={actions}
+                                                                row={row}
+                                                                onRowEdit={(data) => handleRowEdit(data)}
+                                                                onSelectedAction={(data, actionName) => handleSelectMenu(data, actionName)}
+                                                            />
+                                                        </TableCell>
+                                                        : <TableCell style={{ width: '150px' }} align='right'>
+                                                            <IconButton onClick={(event) => handleRowEdit(row)} size={dense ? "small" : "medium"}><EditIcon /></IconButton>
+                                                        </TableCell>}
+                                                </StyledTableRow>
+
+                                            );
+                                        }) : <StyledTableRow style={{ width: '100%' }} />)}
+                            </TableBody>
+                        </Table>
+                    </TableContainer>
+
+                    <TablePagination
+                        rowsPerPageOptions={[10, 30, 50]}
+                        labelDisplayedRows={({ from, to, count }) => { console.log(from, to, count) }}
+                        component="div"
+                        count={data.length}
+                        rowsPerPage={_rowsPerPage}
+                        page={_page}
+                        onChangePage={handleChangePage}
+                        onChangeRowsPerPage={handleChangeRowsPerPage}
+                    />
+                </Grid></Grid>
+            {_isConfirm ? <ConfirmDialog
+                type={title}
+                itemName={itemName}
+                openDialog={_isConfirm}
+                onCancel={(v) => handleCancel(v)}
+                onContinue={(v) => handleDelete(v)} /> : <div />}
+        </div>
+    );
+}
+
+MkTable.propTypes = {
+    history: PropTypes.object,
+    headers: PropTypes.array.isRequired,
+    data: PropTypes.array.isRequired,
+    query: PropTypes.object,
+    onProductBOMClick: PropTypes.func,
+    onActions: PropTypes.func,
+    actions: PropTypes.array,
+    title: PropTypes.string,
+    order: PropTypes.any,
+    orderBy: PropTypes.any,
+    rowsPerPage: PropTypes.any,
+    noMoreToLoad: PropTypes.any,
+    isLoading: PropTypes.any,
+    onChangePaginatePage: PropTypes.any,
+    onGetData: PropTypes.any,
+    onChangeRowPerPage: PropTypes.any,
+    dense: PropTypes.any
+};
+
+export default (MkTable);

+ 1 - 0
src/MkTable/index.js

@@ -0,0 +1 @@
+export { default } from '.';

+ 0 - 4
src/RadioList/RadioList.js

@@ -1,4 +0,0 @@
-function RadioList() {
-    return (<div>radio list</div>);
-}
-export default RadioList;

+ 0 - 1
src/RadioList/index.js

@@ -1 +0,0 @@
-export { default } from '../RadioList';

+ 0 - 287
src/TableTemplate/TableTemplate.js

@@ -1,287 +0,0 @@
-import React, { useEffect } from 'react';
-import PropTypes from 'prop-types';
-import { makeStyles } from '@material-ui/core/styles';
-import Table from '@material-ui/core/Table';
-import TableBody from '@material-ui/core/TableBody';
-import TableCell from '@material-ui/core/TableCell';
-import TableContainer from '@material-ui/core/TableContainer';
-import TableHead from '@material-ui/core/TableHead';
-import TablePagination from '@material-ui/core/TablePagination';
-import TableRow from '@material-ui/core/TableRow';
-import TableSortLabel from '@material-ui/core/TableSortLabel';
-import { Grid } from '@material-ui/core';
-
-function descendingComparator(a, b, orderBy) {
-    if (b[orderBy] < a[orderBy]) {
-        return -1;
-    }
-    if (b[orderBy] > a[orderBy]) {
-        return 1;
-    }
-    return 0;
-}
-
-function getComparator(order, orderBy) {
-    return order === 'desc'
-        ? (a, b) => descendingComparator(a, b, orderBy)
-        : (a, b) => -descendingComparator(a, b, orderBy);
-}
-
-function stableSort(array, comparator) {
-    const stabilizedThis = array.map((el, index) => [el, index]);
-    stabilizedThis.sort((a, b) => {
-        const order = comparator(a[0], b[0]);
-        if (order !== 0) return order;
-        return a[1] - b[1];
-    });
-    return stabilizedThis.map((el) => el[0]);
-}
-
-function EnhancedTableHead(props) {
-    const { classes,
-        order,
-        orderBy,
-        onRequestSort,
-        onRefreshData,
-        headCells } = props;
-    const createSortHandler = (property) => (event) => {
-        onRequestSort(event, property);
-        onRefreshData();
-    };
-
-    return (
-        <TableHead>
-            <TableRow>
-                {headCells.map((headCell) => (
-                    <TableCell
-                        key={headCell.id}
-                        align={headCell.numeric ? 'right' : 'left'}
-                        padding={headCell.disablePadding ? 'none' : 'default'}
-                        sortDirection={orderBy === headCell.id ? order : false}
-                    >
-                        {headCell.id != 'id' ?
-                            <TableSortLabel
-                                active={orderBy === headCell.id}
-                                direction={orderBy === headCell.id ? order : 'asc'}
-                                onClick={createSortHandler(headCell.id)}
-                            >
-                                {headCell.label}
-                                {orderBy === headCell.id ? (
-                                    <span className={classes.visuallyHidden}>
-                                        {order === 'desc' ? 'sorted descending' : 'sorted ascending'}
-                                    </span>
-                                ) : null}
-                            </TableSortLabel>
-                            : <TableSortLabel
-                                hideSortIcon={true}
-                            >
-                                {headCell.label}
-
-                            </TableSortLabel>
-                        }
-
-                    </TableCell>
-                ))}
-            </TableRow>
-        </TableHead>
-    );
-}
-
-EnhancedTableHead.propTypes = {
-    classes: PropTypes.object.isRequired,
-    numSelected: PropTypes.number.isRequired,
-    onRequestSort: PropTypes.func.isRequired,
-    onRefreshData: PropTypes.func.isRequired,
-    onSelectAllClick: PropTypes.func.isRequired,
-    order: PropTypes.oneOf(['asc', 'desc']).isRequired,
-    orderBy: PropTypes.string.isRequired,
-    rowCount: PropTypes.number.isRequired,
-};
-
-const useStyles = makeStyles((theme) => ({
-    root: {
-        width: '100%',
-    },
-    paper: {
-        width: '100%',
-        marginBottom: theme.spacing(2),
-    },
-    table: {
-        minWidth: 750,
-    },
-    visuallyHidden: {
-        border: 0,
-        clip: 'rect(0 0 0 0)',
-        height: 1,
-        margin: -1,
-        overflow: 'hidden',
-        padding: 0,
-        position: 'absolute',
-        top: 20,
-        width: 1,
-    },
-    underline: {
-        "&&&:before": {
-            borderBottom: "none"
-        },
-        "&&:after": {
-            borderBottom: "none"
-        }
-    }
-}));
-
-function TableTemplate(props) {
-    const classes = useStyles();
-    const {
-        data = [],
-        headers = [],
-        onUpdateData,
-        onReloadData,
-        onChangePage,
-        onChangeRowsPerPage,
-        rowsPerPage = 10,
-        page = 0,
-        order = 'asc',
-        orderBy
-    } = props;
-
-    const [selected, setSelected] = React.useState([]);
-    const [dense, setDense] = React.useState(false);
-    const [rowDataPerPage, setRowsPerPage] = React.useState(rowsPerPage != undefined ? rowsPerPage : 10);
-    const [paginatePage, setPage] = React.useState(page != undefined ? page : 0);
-    const [paginateOrder, setOrder] = React.useState(order != undefined ? order : 'asc');
-    const [paginateOrderBy, setOrderBy] = React.useState(orderBy != undefined ? orderBy : 'name');
-
-    var offset = paginatePage * rowDataPerPage;
-
-    const handleRequestSort = (event, property) => {
-        const isAsc = orderBy === property && order === 'asc';
-        setOrder(isAsc ? 'desc' : 'asc');
-        setOrderBy(property);
-    };
-
-    const handleSelectAllClick = (event) => {
-        if (event.target.checked) {
-            const newSelecteds = data.map((n) => n.name);
-            setSelected(newSelecteds);
-            return;
-        }
-        setSelected([]);
-    };
-
-    const handleClick = (event, rowdata) => {
-        onUpdateData(true, rowdata);
-    };
-
-    const handleChangePage = (event, newPage) => {
-        onChangePage(newPage);
-
-    };
-
-    const handleReloadData = () => {
-        onReloadData();
-    }
-
-    const handleChangeRowsPerPage = (event) => {
-        setRowsPerPage(parseInt(event.target.value, 10));
-        onChangeRowsPerPage(parseInt(event.target.value));
-        onReloadData();
-    };
-
-    const isSelected = (name) => selected.indexOf(name) !== -1;
-
-    const emptyRows = rowsPerPage - Math.min(rowsPerPage, data.length - page * rowsPerPage);
-
-    return (
-        <div className={classes.root}>
-            <Grid container>
-                <Grid item style={{ marginRight: '10%' }}>
-
-                    <TableContainer>
-                        <Table
-                            className={classes.table}
-                            aria-labelledby="tableTitle"
-                            size={dense ? 'small' : 'medium'}
-                            aria-label="enhanced table"
-                        >
-                            <EnhancedTableHead
-                                classes={classes}
-                                numSelected={selected.length}
-                                headCells={headers}
-                                order={order}
-                                orderBy={orderBy}
-                                onSelectAllClick={handleSelectAllClick}
-                                onRequestSort={handleRequestSort}
-                                onRefreshData={handleReloadData}
-                                rowCount={data.length}
-                            />
-                            <TableBody>
-                                {data.length != 0 ? stableSort(data, getComparator(order, orderBy))
-                                    .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
-                                    .map((row, index) => {
-                                        const isItemSelected = isSelected(row.name);
-                                        const labelId = `enhanced-table-checkbox-${index}`;
-
-                                        return (
-                                            <TableRow
-                                                hover
-                                                onClick={(event) => handleClick(event, row)}
-                                                role="checkbox"
-                                                aria-checked={isItemSelected}
-                                                tabIndex={-1}
-                                                key={index}
-                                                selected={isItemSelected}
-                                            >
-
-                                                {headers.map((h, i) => {
-                                                    if (h.id == 'id') {
-                                                        return (<TableCell key={h.id} align="right">{++offset}</TableCell>);
-                                                    } else {
-                                                        return (<TableCell key={h.id} align="right">{row[h.id]}</TableCell>);
-                                                    }
-                                                })}
-
-                                            </TableRow>
-                                        );
-                                    }) : <div></div>}
-                                {emptyRows > 0 && (
-                                    <TableRow style={{ height: (dense ? 33 : 53) * emptyRows }}>
-                                        <TableCell colSpan={6} />
-                                    </TableRow>
-                                )}
-                            </TableBody>
-                        </Table>
-                    </TableContainer>
-
-                    <TablePagination
-                        rowsPerPageOptions={[5, 10, 20, 30]}
-                        labelDisplayedRows={function ({ from, to, count }) { }}
-                        component="div"
-                        count={data.length}
-                        rowsPerPage={rowsPerPage}
-                        rowsPerPage={rowsPerPage}
-                        page={page}
-                        onChangePage={handleChangePage}
-                        onChangeRowsPerPage={handleChangeRowsPerPage}
-                    />
-                </Grid></Grid>
-        </div>
-    );
-}
-
-TableTemplate.propTypes = {
-    history: PropTypes.object,
-    headers: PropTypes.array.isRequired,
-    data: PropTypes.array.isRequired,
-    onUpdateData: PropTypes.func,
-    onReloadData: PropTypes.func,
-    onChangePage: PropTypes.func,
-    onChangeRowsPerPage: PropTypes.func,
-    query: PropTypes.object,
-    page: PropTypes.any,
-    rowsPerPage: PropTypes.any,
-    order: PropTypes.any,
-    orderBy: PropTypes.any
-};
-
-export default (TableTemplate);

+ 0 - 1
src/TableTemplate/index.js

@@ -1 +0,0 @@
-export { default } from '../TableTemplate';

+ 3 - 5
src/index.js

@@ -1,6 +1,4 @@
 export { default as List } from './List/List';
-export { default as FieldList } from './FieldList/FieldList';
-export { default as TableTemplate } from './TableTemplate/TableTemplate';
-export { default as InfoPage } from './InfoPage/InfoPage';
-export { default as CheckboxList } from './CheckboxList/CheckboxList';
-export { default as RadioList } from './RadioList/RadioList';
+export { default as MkForm } from './MkForm/MkForm';
+export { default as MkTable } from './MkTable/MkTable';
+export { default as MkInfo } from './MkInfo/MkInfo';

Some files were not shown because too many files changed in this diff