Compare commits
14 Commits
a3c380ffd1
...
1050709fd2
| Author | SHA1 | Date | |
|---|---|---|---|
| 1050709fd2 | |||
| 9d499eb986 | |||
| 85b4afd835 | |||
| 6e6ad45149 | |||
| 587e8ef70d | |||
| 9c9c584a84 | |||
| 03ee5d6fa8 | |||
| ec75fb476f | |||
| 2ed7998897 | |||
| ab4de61b42 | |||
| 0ef729256f | |||
| 5bafe0e1a2 | |||
| eec749c029 | |||
| 47eebd3e5a |
3
.gitignore
vendored
3
.gitignore
vendored
@ -10,13 +10,16 @@
|
||||
|
||||
# production
|
||||
/build
|
||||
build.zip
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env
|
||||
.env.local
|
||||
.env.development
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
|
||||
5
package-lock.json
generated
5
package-lock.json
generated
@ -13561,6 +13561,11 @@
|
||||
"symbol-observable": "^1.2.0"
|
||||
}
|
||||
},
|
||||
"redux-thunk": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
|
||||
"integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
|
||||
},
|
||||
"regenerate": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz",
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
"react-scripts": "4.0.0",
|
||||
"reactstrap": "^8.7.1",
|
||||
"redux": "^4.0.5",
|
||||
"redux-thunk": "^2.3.0",
|
||||
"web-vitals": "^0.2.4",
|
||||
"yup": "^0.32.5"
|
||||
},
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" href="main.css">
|
||||
@ -16,17 +15,14 @@
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://npmcdn.com/react-bootstrap-table/dist/react-bootstrap-table-all.min.css">
|
||||
</link>
|
||||
|
||||
<title>Migrations Tracker</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!-- Compiled and minified JavaScript -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
|
||||
<script src="https://npmcdn.com/react-bootstrap-table/dist/react-bootstrap-table.min.js"></script>
|
||||
<!-- This breaks things -->
|
||||
<!-- <script src="https://npmcdn.com/react-bootstrap-table/dist/react-bootstrap-table.min.js"></script> -->
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -1,9 +1,10 @@
|
||||
import React, { Component } from "react";
|
||||
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
|
||||
|
||||
// Store
|
||||
import { Provider } from "react-redux";
|
||||
import store from "../redux/store";
|
||||
// Store currently in progress
|
||||
|
||||
// import { Provider } from "react-redux";
|
||||
// import store from "../redux/store";
|
||||
|
||||
// Routes
|
||||
import Migrations from "./root/Pages/Migrations";
|
||||
@ -21,73 +22,61 @@ import Navigation from "./root/Navigation";
|
||||
class App extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<Router>
|
||||
<Navigation />
|
||||
<div className="row">
|
||||
<div className="col s12 m4 13">
|
||||
<div className="container-fluid">
|
||||
<Switch>
|
||||
<Route exact path="/" component={Home} />
|
||||
<Route exact path="/book" component={Book} />
|
||||
<Route exact path="/migrations" component={Migrations} />
|
||||
<Route exact path="/reports" component={Reports} />
|
||||
<Route path="/migrations/:migrationId" component={IDSingle} />
|
||||
<Route
|
||||
exact
|
||||
path="/upcoming-migrations"
|
||||
render={(props) => (
|
||||
<GenericList {...props} APILINK="/pending/" />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/missed"
|
||||
render={(props) => (
|
||||
<GenericList {...props} APILINK="/missed/" />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/completed"
|
||||
render={(props) => (
|
||||
<GenericList {...props} APILINK="/completed/" />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/pending-terminations"
|
||||
render={(props) => (
|
||||
<GenericList {...props} APILINK="/waitingterm/" />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/all-terminations"
|
||||
render={(props) => (
|
||||
<GenericList {...props} APILINK="/pendingterm/" />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/historical-migrations"
|
||||
render={(props) => (
|
||||
<GenericList {...props} APILINK="/all/" />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/booked"
|
||||
render={(props) => (
|
||||
<GenericList {...props} APILINK="/booked/" />
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Router>
|
||||
</Provider>
|
||||
// <Provider store={store}>
|
||||
<Router>
|
||||
<Navigation />
|
||||
<div className="col 13">
|
||||
<Switch>
|
||||
<Route exact path="/" component={Home} />
|
||||
<Route exact path="/book" component={Book} />
|
||||
<Route exact path="/migrations" component={Migrations} />
|
||||
<Route exact path="/reports" component={Reports} />
|
||||
<Route path="/migrations/:migrationId" component={IDSingle} />
|
||||
<Route
|
||||
exact
|
||||
path="/upcoming-migrations"
|
||||
render={(props) => <GenericList {...props} APILINK="/pending/" />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/missed"
|
||||
render={(props) => <GenericList {...props} APILINK="/missed/" />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/completed"
|
||||
render={(props) => (
|
||||
<GenericList {...props} APILINK="/completed/" />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/pending-terminations"
|
||||
render={(props) => (
|
||||
<GenericList {...props} APILINK="/waitingterm/" />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/all-terminations"
|
||||
render={(props) => (
|
||||
<GenericList {...props} APILINK="/pendingterm/" />
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/historical-migrations"
|
||||
render={(props) => <GenericList {...props} APILINK="/all/" />}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path="/booked"
|
||||
render={(props) => <GenericList {...props} APILINK="/booked/" />}
|
||||
/>
|
||||
</Switch>
|
||||
</div>
|
||||
</Router>
|
||||
// </Provider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
@ -2,6 +2,8 @@ import axios from "axios";
|
||||
|
||||
// Axios create, exporting callAPI
|
||||
|
||||
|
||||
export const callAPI = axios.create({
|
||||
baseURL: process.env.REACT_APP_API_ADDRESS,
|
||||
headers: {'Authorization': "Api-Key " + process.env.REACT_APP_API_KEY}
|
||||
});
|
||||
|
||||
@ -10,6 +10,7 @@ export const Error = () => (
|
||||
<span className="card-title">
|
||||
<i className="large material-icons">do_not_disturb</i>
|
||||
</span>
|
||||
<h3>API OFFLINE</h3>
|
||||
</center>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -3,6 +3,8 @@ import React, { Component } from "react";
|
||||
import { callAPI } from "../actions/API";
|
||||
import Cards from "./Pages/Cards";
|
||||
import GenericList from "../root/Pages/GenericList";
|
||||
import TimeSlotHelper from "./Pages/TimeSlotHelper";
|
||||
|
||||
import { UList } from "../root/common/Functionality/UnorderedList";
|
||||
import { builfArrayFromObject } from "../actions/Error";
|
||||
|
||||
@ -23,6 +25,19 @@ export class Home extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
getTimeslot(days) {
|
||||
callAPI
|
||||
.get("/timeslots/?days=" + days)
|
||||
.then((request) => {
|
||||
return request.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({
|
||||
error: error,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
callAPI
|
||||
.get("/")
|
||||
@ -36,40 +51,28 @@ export class Home extends Component {
|
||||
error: error,
|
||||
});
|
||||
});
|
||||
callAPI
|
||||
.get("/timeslots")
|
||||
.then((request) => {
|
||||
this.setState({
|
||||
timeslots: request.data,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
this.setState({
|
||||
error: error,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="divider"></div>
|
||||
|
||||
<div className="section">
|
||||
<div className="col s7">
|
||||
<div className="container">
|
||||
<div className="row">
|
||||
<div className="col s12"></div>
|
||||
</div>
|
||||
<div className="row">
|
||||
<div className="col s4 18">
|
||||
<Cards migs={this.state.migs} />
|
||||
</div>
|
||||
<div className="col s5">
|
||||
<p>Current availability for {Date()}</p>
|
||||
<UList listItems={builfArrayFromObject(this.state.timeslots)} />
|
||||
<div className="col s8 12">
|
||||
{/* <p>Current availability for {Date()}</p>
|
||||
<UList listItems={builfArrayFromObject(this.state.timeslots)} /> */}
|
||||
{/* <TimeSlotHelper /> */}
|
||||
</div>
|
||||
<div className="divider"></div>
|
||||
<div className="section">
|
||||
<div className="row">
|
||||
<div className="col s12">
|
||||
<GenericList APILINK="/pending/" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="divider"></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import React, { Component } from "react";
|
||||
|
||||
import { callAPI } from "../../actions/API";
|
||||
import FormPage from "../common/Forms/FormPage";
|
||||
|
||||
// Parent page for the Book component,
|
||||
@ -10,9 +11,22 @@ export default class Book extends Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
migs: [],
|
||||
timeslots: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
callAPI
|
||||
.get('/gettimeslots/')
|
||||
.then( (response) => {
|
||||
this.setState({
|
||||
timeslots: response.data
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.timeslots.length > 0) {
|
||||
return (
|
||||
<div className="container-fluid">
|
||||
<div className="section">
|
||||
@ -22,10 +36,13 @@ export default class Book extends Component {
|
||||
|
||||
<div className="section">
|
||||
<div className="col s12">
|
||||
<FormPage />
|
||||
<FormPage timeslots={this.state.timeslots} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}else{
|
||||
return(<div></div>)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React, { Component } from "react";
|
||||
import CompTable from "../common/Tables/CompTable";
|
||||
import { callAPI } from "../../actions/API"
|
||||
import { callAPI } from "../../actions/API";
|
||||
import { Error } from "../../actions/Error";
|
||||
|
||||
// Missing parent page,
|
||||
@ -18,9 +18,10 @@ class GenericList extends Component {
|
||||
}
|
||||
|
||||
renderItems() {
|
||||
console.log(this.props.APILINK)
|
||||
if (!this.state.error) {
|
||||
return <CompTable data={callAPI(this.props.APILINK)} />;
|
||||
return (
|
||||
<CompTable data={callAPI(this.props.APILINK)} key={this.state.error} />
|
||||
);
|
||||
} else {
|
||||
console.log("error");
|
||||
return <Error />;
|
||||
@ -28,19 +29,7 @@ class GenericList extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="row">
|
||||
<div className="divider"></div>
|
||||
<div className="section">
|
||||
<div className="col s12"></div>
|
||||
</div>
|
||||
<div className="divider"></div>
|
||||
<div className="section">
|
||||
<div className="col s12">{this.renderItems()}</div>
|
||||
</div>
|
||||
<div className="divider"></div>
|
||||
</div>
|
||||
);
|
||||
return <div>{this.renderItems()}</div>;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
54
src/components/root/Pages/TimeSlotHelper.js
Normal file
54
src/components/root/Pages/TimeSlotHelper.js
Normal file
@ -0,0 +1,54 @@
|
||||
import React, { Component } from "react";
|
||||
import TimeSlots from "../common/Tables/TimeSlots";
|
||||
import { callAPI } from "../../actions/API";
|
||||
import { Error } from "../../actions/Error";
|
||||
|
||||
// Missing parent page,
|
||||
// Most of the good stuff is happening in UpcomingSingle, which does the
|
||||
// main rendering of the table,
|
||||
// may want to eventually do the API call here, to re-use the table
|
||||
// instead of duplicating it.
|
||||
|
||||
class GenericList extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
error: false,
|
||||
timeslots: [],
|
||||
bookedslots: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
callAPI.get("/gettimeslots/").then((response) => {
|
||||
this.setState({
|
||||
timeslots: response.data,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderItems() {
|
||||
if (!this.state.error) {
|
||||
return (
|
||||
<TimeSlots
|
||||
timeSlots={this.state.timeslots}
|
||||
bookedSlots={this.state.bookedslots}
|
||||
key={this.state.timeslots}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return <Error />;
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div>{this.renderItems()}</div>;
|
||||
}
|
||||
}
|
||||
export default GenericList;
|
||||
|
||||
// if (this.state.timeslots > 0) {
|
||||
// else {
|
||||
// return <Error />;
|
||||
// }
|
||||
// }
|
||||
@ -23,16 +23,8 @@ const InputValidation = Yup.object().shape({
|
||||
.required("Please enter a domain"),
|
||||
username: Yup.string().min(2, "Too Short!").required("Required"),
|
||||
original_server: Yup.string()
|
||||
.matches(
|
||||
/^((([1-9]?\d|1\d\d|2[0-5][0-5]|2[0-4]\d)\.){3}([1-9]?\d|1\d\d|2[0-5][0-5]|2[0-4]\d))|(((https?):\/\/)?(www.)?[a-z0-9]+(\.[a-z]{2,}){1,3}(#?\/?[a-zA-Z0-9#]+)*\/?(\?[a-zA-Z0-9-_]+=[a-zA-Z0-9-%]+&?)?)|([a-z0-9]{0,4}-[a-z0-9]{0,2}-[a-z0-9]{0,3})$/i,
|
||||
"Please enter a valid IPv4 Address or domain"
|
||||
)
|
||||
.required("Please enter a valid IPv4 or domain"),
|
||||
new_server: Yup.string()
|
||||
.matches(
|
||||
/^((([1-9]?\d|1\d\d|2[0-5][0-5]|2[0-4]\d)\.){3}([1-9]?\d|1\d\d|2[0-5][0-5]|2[0-4]\d))|(((https?):\/\/)?(www.)?[a-z0-9]+(\.[a-z]{2,}){1,3}(#?\/?[a-zA-Z0-9#]+)*\/?(\?[a-zA-Z0-9-_]+=[a-zA-Z0-9-%]+&?)?)|([a-z0-9]{0,4}-[a-z0-9]{0,2}-[a-z0-9]{0,3})$/i,
|
||||
"Please enter a valid IPv4 Address or domain"
|
||||
)
|
||||
.required("Please enter a valid IPv4 or domain"),
|
||||
agent_booked: Yup.string()
|
||||
.min(2, "Too short!")
|
||||
@ -44,7 +36,7 @@ const InputValidation = Yup.object().shape({
|
||||
booked_date: Yup.date().required("Please enter a date!"),
|
||||
});
|
||||
|
||||
export const CPanelBooking = () => {
|
||||
export const CPanelBooking = (timeslots) => {
|
||||
const [respID, setRespID] = useState(0);
|
||||
const [error, setError] = useState(0);
|
||||
|
||||
@ -56,7 +48,7 @@ export const CPanelBooking = () => {
|
||||
const onSubmit = async (values, { setSubmitting, resetForm }) => {
|
||||
console.log(values);
|
||||
callAPI
|
||||
.post("/", values)
|
||||
.post("/book/", values)
|
||||
.then(function (response) {
|
||||
// console.log(response);
|
||||
// add function here
|
||||
@ -70,6 +62,7 @@ export const CPanelBooking = () => {
|
||||
});
|
||||
setSubmitting(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
@ -108,12 +101,7 @@ export const CPanelBooking = () => {
|
||||
className="has-success"
|
||||
>
|
||||
<option>Select</option>
|
||||
<option>00:00-03:00</option>
|
||||
<option>03:00-06:00</option>
|
||||
<option>06:00-09:00</option>
|
||||
<option>08:00-12:00</option>
|
||||
<option>12:00-18:00</option>
|
||||
<option>18:00-00:00</option>
|
||||
{timeslots.timeslots.map((slot) => <option>{slot}</option>)}
|
||||
</Input>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
@ -13,7 +13,7 @@ import classnames from "classnames";
|
||||
import { CPanelBooking } from "./CPanelBooking";
|
||||
import EmailBooking from "./EmailBooking";
|
||||
|
||||
const FormPage = ({ item }) => {
|
||||
const FormPage = ({ timeslots, item }) => {
|
||||
const [activeTab, setActiveTab] = useState("1");
|
||||
|
||||
const toggle = (tab) => {
|
||||
@ -23,7 +23,6 @@ const FormPage = ({ item }) => {
|
||||
// Parent page from the Book section,
|
||||
// Can be expanded to offer email migration bookings,
|
||||
// elements below do the POST requests.
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Nav tabs>
|
||||
@ -52,7 +51,7 @@ const FormPage = ({ item }) => {
|
||||
<TabPane tabId="1">
|
||||
<Row>
|
||||
<Col sm="12">
|
||||
<CPanelBooking />
|
||||
<CPanelBooking timeslots={timeslots} />
|
||||
</Col>
|
||||
</Row>
|
||||
</TabPane>
|
||||
|
||||
@ -5,11 +5,11 @@ export function UList(props) {
|
||||
<div>
|
||||
<ul>
|
||||
{props.listItems.map((item) => (
|
||||
<li liClass="white-text" className={props.liClass}>
|
||||
<li liclass="white-text" className={props.liclass} key={item}>
|
||||
{item}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,6 @@ import ToolkitProvider, {
|
||||
const CompTable = (props) => {
|
||||
const [list, setList] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const { SearchBar } = Search;
|
||||
const { ExportCSVButton } = CSVExport;
|
||||
const sizePerPageRenderer = ({
|
||||
@ -107,7 +106,6 @@ const CompTable = (props) => {
|
||||
),
|
||||
},
|
||||
{ dataField: "booked_date", text: "Booked Date", sort: true },
|
||||
// { dataField: "booked_time", text: "Booked Time", sort: true },
|
||||
{ dataField: "agent_booked", text: "Agent initials", sort: true },
|
||||
{
|
||||
dataField: "domain",
|
||||
@ -120,9 +118,7 @@ const CompTable = (props) => {
|
||||
{ dataField: "migration_type", text: "Type", sort: true },
|
||||
{ dataField: "original_server", text: "Original Server", sort: true },
|
||||
{ dataField: "new_server", text: "New Server", sort: true },
|
||||
// { dataField: "term_date", text: "Termination Date", sort: true },
|
||||
{ dataField: "notes", text: "Notes", sort: true },
|
||||
// { dataField: "submit_time", text: "Submit Time", sort: true },
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
@ -130,7 +126,7 @@ const CompTable = (props) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="HistoricalSingle">
|
||||
<div>
|
||||
{loading ? (
|
||||
<ToolkitProvider
|
||||
keyField="name"
|
||||
@ -138,12 +134,13 @@ const CompTable = (props) => {
|
||||
columns={columns}
|
||||
search
|
||||
exportCSV
|
||||
key={columns.id}
|
||||
>
|
||||
{(props) => (
|
||||
<div>
|
||||
<div className="serSec">
|
||||
<h3 className="hdrOne"></h3>
|
||||
<SearchBar {...props.searchProps} />
|
||||
<SearchBar {...props.searchProps} key={columns} />
|
||||
</div>
|
||||
|
||||
<div className="table-responsive">
|
||||
@ -154,9 +151,11 @@ const CompTable = (props) => {
|
||||
striped
|
||||
hover
|
||||
condensed
|
||||
key={columns.id}
|
||||
keyField="id"
|
||||
/>
|
||||
</div>
|
||||
<ExportCSVButton {...props.csvProps}>
|
||||
<ExportCSVButton {...props.csvProps} key={columns}>
|
||||
Export CSV!!
|
||||
</ExportCSVButton>
|
||||
</div>
|
||||
|
||||
133
src/components/root/common/Tables/TimeSlots.js
Normal file
133
src/components/root/common/Tables/TimeSlots.js
Normal file
@ -0,0 +1,133 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import BootstrapTable from "react-bootstrap-table-next";
|
||||
import paginationFactory from "react-bootstrap-table2-paginator";
|
||||
import * as ReactBootstrap from "react-bootstrap";
|
||||
import filterFactory from "react-bootstrap-table2-filter";
|
||||
import ToolkitProvider, {
|
||||
Search,
|
||||
CSVExport,
|
||||
} from "react-bootstrap-table2-toolkit";
|
||||
|
||||
// notes
|
||||
//
|
||||
|
||||
const TimeSlots = (props) => {
|
||||
const [list, setList, setTimeSlots, setBookedSlots] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { SearchBar } = Search;
|
||||
const { ExportCSVButton } = CSVExport;
|
||||
const sizePerPageRenderer = ({
|
||||
options,
|
||||
currSizePerPage,
|
||||
onSizePerPageChange,
|
||||
}) => (
|
||||
<div className="btn-group" role="group">
|
||||
{options.map((option) => {
|
||||
const isSelect = currSizePerPage === `${option.page}`;
|
||||
return (
|
||||
<button
|
||||
key={option.text}
|
||||
type="button"
|
||||
onClick={() => onSizePerPageChange(option.page)}
|
||||
className={`btn ${isSelect ? "btn-secondary" : "btn-success"}`}
|
||||
>
|
||||
{option.text}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
||||
const getListData = async () => {
|
||||
try {
|
||||
const setList = await props.setList;
|
||||
setList();
|
||||
setLoading(true);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const options = {
|
||||
// paginationSize: 4,
|
||||
// pageStartIndex: 0,
|
||||
// alwaysShowAllBtns: true, // Always show next and previous button
|
||||
// withFirstAndLast: false, // Hide the going to First and Last page button
|
||||
// hideSizePerPage: true, // Hide the sizePerPage dropdown always
|
||||
// hidePageListOnlyOnePage: true, // Hide the pagination list when only one page
|
||||
// firstPageText: "First",
|
||||
// prePageText: "Back",
|
||||
nextPageText: "Next",
|
||||
lastPageText: "Last",
|
||||
// nextPageTitle: "First page",
|
||||
// prePageTitle: "Pre page",
|
||||
// firstPageTitle: "Next page",
|
||||
// lastPageTitle: "Last page",
|
||||
// showTotal: true,
|
||||
// disablePageTitle: true,
|
||||
// sizePerPageList: [
|
||||
// {
|
||||
// text: "50",
|
||||
// value: 50,
|
||||
// },
|
||||
// {
|
||||
// text: "100",
|
||||
// value: 100,
|
||||
// },
|
||||
// ],
|
||||
sizePerPageRenderer, // A numeric array is also available. the purpose of above example is custom the text
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{ dataField: "bookedSlots", text: "bookedslots", sort: true },
|
||||
{ dataField: "timeSlots", text: "timeslots", sort: true },
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
getListData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{loading ? (
|
||||
<ToolkitProvider
|
||||
keyField="name"
|
||||
data={list}
|
||||
columns={columns}
|
||||
search
|
||||
exportCSV
|
||||
key={columns.id}
|
||||
keyField="id"
|
||||
>
|
||||
{(props) => (
|
||||
<div>
|
||||
<div className="serSec">
|
||||
<h3 className="hdrOne"></h3>
|
||||
<SearchBar {...props.searchProps} key={columns} />
|
||||
</div>
|
||||
|
||||
<div className="table-responsive">
|
||||
<BootstrapTable
|
||||
{...props.baseProps}
|
||||
filter={filterFactory()}
|
||||
pagination={paginationFactory(options)}
|
||||
striped
|
||||
hover
|
||||
condensed
|
||||
key={columns.id}
|
||||
/>
|
||||
</div>
|
||||
<ExportCSVButton {...props.csvProps} key={columns}>
|
||||
Export CSV!!
|
||||
</ExportCSVButton>
|
||||
</div>
|
||||
)}
|
||||
</ToolkitProvider>
|
||||
) : (
|
||||
<ReactBootstrap.Spinner animation="border" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TimeSlots;
|
||||
@ -1,13 +0,0 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
@ -1,6 +1,5 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import "./index.css";
|
||||
import App from "./components/App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
|
||||
@ -11,7 +10,4 @@ ReactDOM.render(
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
export const ADD_ARTICLE = "ADD_ARTICLE";
|
||||
export const GET_MIGRATIONS = "GET_MIGRATIONS";
|
||||
export const DATA_LOADED = "DATA_LOADED";
|
||||
export const API_ERRORED = "API_ERRORED";
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { ADD_ARTICLE } from "../constants/action-types";
|
||||
import { GET_MIGRATIONS } from "../constants/action-types";
|
||||
|
||||
const forbiddenWords = ["spam", "money"];
|
||||
|
||||
@ -6,7 +6,7 @@ export function forbiddenWordsMiddleware({ dispatch }) {
|
||||
return function (next) {
|
||||
return function (action) {
|
||||
// do your stuff
|
||||
if (action.type === ADD_ARTICLE) {
|
||||
if (action.type === GET_MIGRATIONS) {
|
||||
const foundWord = forbiddenWords.filter((word) =>
|
||||
action.payload.title.includes(word)
|
||||
);
|
||||
|
||||
@ -1,20 +1,21 @@
|
||||
import { ADD_ARTICLE, DATA_LOADED } from "../constants/action-types";
|
||||
import { GET_MIGRATIONS, DATA_LOADED } from "../constants/action-types";
|
||||
|
||||
const initialState = {
|
||||
articles: [],
|
||||
remoteArticles: [],
|
||||
migs: [],
|
||||
timeslots: [],
|
||||
error: false,
|
||||
};
|
||||
|
||||
function rootReducer(state = initialState, action) {
|
||||
if (action.type === ADD_ARTICLE) {
|
||||
if (action.type === GET_MIGRATIONS) {
|
||||
return Object.assign({}, state, {
|
||||
articles: state.articles.concat(action.payload),
|
||||
migs: state.migs.concat(action.payload),
|
||||
});
|
||||
}
|
||||
|
||||
if (action.type === DATA_LOADED) {
|
||||
return Object.assign({}, state, {
|
||||
remoteArticles: state.remoteArticles.concat(action.payload),
|
||||
timeslots: state.timeslots.concat(action.payload),
|
||||
});
|
||||
}
|
||||
return state;
|
||||
|
||||
Reference in New Issue
Block a user