Skip to content

Commit

Permalink
Add deliverer assignment section
Browse files Browse the repository at this point in the history
  • Loading branch information
mrafei committed Jul 8, 2020
1 parent d16bda5 commit 9c1a84c
Show file tree
Hide file tree
Showing 17 changed files with 495 additions and 105 deletions.
20 changes: 20 additions & 0 deletions src/components/CheckBox/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from "react";

function CheckBox({ text, onChange, checked, label, className = "" }) {
return (
<label className={`checkbox-container mb-0 ${className}`} htmlFor={label}>
<input
className="form-check-input"
type="checkbox"
checked={checked}
onChange={(e) => {
onChange(e.target.checked);
}}
id={label}
/>
<span className="checkmark" />
{text}
</label>
);
}
export default CheckBox;
5 changes: 3 additions & 2 deletions src/components/Layout/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ const subRoutes = [
[],
[],
[
{ id: 1, title: "لیست پیک‌ها", path: "/delivery/deliverers" },
{ id: 1, title: "تخصیص پیک", path: "/delivery/assign" },
{ id: 2, title: "لیست پیک‌ها", path: "/delivery/deliverers" },
{
id: 2,
id: 3,
title: "لیست تحویل‌ها",
path: "/delivery/deliveries",
},
Expand Down
34 changes: 29 additions & 5 deletions src/components/OrderCard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ import moment from "moment-jalaali";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";

import { ellipseText, englishNumberToPersianNumber, priceFormatter } from "../../../utils/helper";
import {
ellipseText,
englishNumberToPersianNumber,
noOp,
priceFormatter,
} from "../../../utils/helper";
import Icon from "../Icon";
import { ICONS } from "../../../assets/images/icons";
import CheckBox from "../CheckBox";

function OrderCard({ order, link }) {
function OrderCard({ order, link, isBold, hasCheck, selected, onSelect }) {
const {
final_price: totalPrice,
user_address: userAddress,
Expand All @@ -26,7 +32,15 @@ function OrderCard({ order, link }) {
(orderStatus === 0 && "#168FD4") || (orderStatus === 2 && "#E13F18") || "#67b977";
return (
<>
<Link to={link} className="d-flex px-0 u-cursor-pointer c-order-card overflow-hidden">
<Link
to={link}
onClick={(e) => {
if (hasCheck) {
e.preventDefault();
onSelect(selected);
}
}}
className="d-flex px-0 u-cursor-pointer c-order-card overflow-hidden">
<div
style={{
minWidth: 4,
Expand All @@ -35,11 +49,21 @@ function OrderCard({ order, link }) {
/>
<div
className={`d-flex w-100 text-center py-1 ${
order.order_status !== 0
!isBold
? "u-background-melo-grey u-text-darkest-grey"
: "u-background-white u-fontWeightBold u-text-black"
} pl-2`}>
<div className="d-flex px-2 align-items-center justify-content-center" style={{ width: 90 }}>
{hasCheck && (
<CheckBox
checked={selected}
onChange={noOp}
label={`defaultCheck${order.id}`}
className="mr-2"
/>
)}
<div
className="d-flex px-2 align-items-center justify-content-center"
style={{ width: 90 }}>
{orderDate.getMonth() === nowDate.getMonth() &&
orderDate.getFullYear() === nowDate.getFullYear() &&
orderDate.getDate() === nowDate.getDate() ? (
Expand Down
6 changes: 3 additions & 3 deletions src/components/Pagination/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function Pagination({ location, pagination }) {
<div className="d-flex justify-content-center align-items-center">
{pages[0] + 1 < pagination.pagesCount && (
<div className="d-flex align-items-center">
<Link to={`${location.pathname}?page=${pagination.pagesCount}`} className="py-1 px-2">
<Link to={`${location.pathname}?page=${pagination.pagesCount}`} className="px-2">
<div className="u-border-radius-50-percent u-text-darkest-grey">
{englishNumberToPersianNumber(pagination.pagesCount)}
</div>
Expand All @@ -41,7 +41,7 @@ function Pagination({ location, pagination }) {
{pages.map((p) => (
<Link key={`page-${p}`} to={`${location.pathname}?page=${p + 1}`}>
<div
className="u-border-radius-4 py-1 px-2"
className="u-border-radius-4 px-2"
style={{
backgroundColor: p + 1 === +page ? "#168fd5" : "white",
fontWeight: p + 1 === +page ? "bold" : "normal",
Expand All @@ -54,7 +54,7 @@ function Pagination({ location, pagination }) {
{pages[pages.length - 1] > 0 && (
<div className="d-flex align-items-center">
<span>...</span>
<Link to={`${location.pathname}?page=${1}`} className="py-1 px-2">
<Link to={`${location.pathname}?page=${1}`} className="px-2">
<div className="u-border-radius-50-percent u-text-darkest-grey">۱</div>
</Link>
</div>
Expand Down
6 changes: 5 additions & 1 deletion src/containers/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import CreateDeliverer from "../CreateDeliverer";
import EditDeliverer from "../EditDeliverer";
import DeliveriesList from "../DeliveriesList";
import PrinterSettings from "../PrinterSettings";
import AssignDeliverer from "../AssignDeliverer";

const App = function ({
history,
Expand Down Expand Up @@ -74,14 +75,17 @@ const App = function ({
<Route exact path="/login" component={Login} />
<Route exact path="/online-orders/:id" component={OnlineOrder} />
<Route exact path="/online-orders" component={OnlineOrders} />

<Route exact path="/delivery/deliverers/new" component={CreateDeliverer} />
<Route exact path="/delivery/deliverers/:id" component={EditDeliverer} />
<Route exact path="/delivery/assign" component={AssignDeliverer} />
<Route exact path="/delivery/deliverers" component={DeliverersList} />
<Route exact path="/delivery/deliveries" component={DeliveriesList} />

<Route exact path="/settings/printer" component={PrinterSettings} />

<Redirect path="/settings" to="/settings/printer" />
<Redirect path="/delivery" to="/delivery/deliverers" />
<Redirect path="/delivery" to="/delivery/assign" />
<Redirect path="/" to="/online-orders" />
</Switch>
</Layout>
Expand Down
39 changes: 39 additions & 0 deletions src/containers/AssignDeliverer/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
*
* Admin actions
*
*/

import {
SET_FOOD_ADMIN_ORDERS,
DEFAULT_ACTION,
GET_FOOD_ADMIN_ORDERS,
SET_DELIVERERS,
} from "./constants";

export function defaultAction() {
return {
type: DEFAULT_ACTION,
};
}

export function getFoodAdminOrders(page) {
return {
type: GET_FOOD_ADMIN_ORDERS,
data: page,
};
}

export function setFoodAdminOrders(data, pagination) {
return {
type: SET_FOOD_ADMIN_ORDERS,
data,
pagination,
};
}
export function setDeliverers(data) {
return {
type: SET_DELIVERERS,
data,
};
}
12 changes: 12 additions & 0 deletions src/containers/AssignDeliverer/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
*
* Admin constants
*
*/

export const DEFAULT_ACTION = 'app/AssignDeliverer/DEFAULT_ACTION';
export const GET_FOOD_ADMIN_ORDERS = 'app/AssignDeliverer/GET_FOOD_ADMIN_ORDERS';
export const SET_FOOD_ADMIN_ORDERS = 'app/AssignDeliverer/SET_FOOD_ADMIN_ORDERS';
export const SET_DELIVERERS = 'app/AssignDeliverer/SET_DELIVERERS';

export const ORDERS_PAGE_SIZE = 20;
182 changes: 182 additions & 0 deletions src/containers/AssignDeliverer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import "../../../styles/_main.scss";
import { withRouter } from "react-router-dom";
import { compose } from "redux";
import React, { memo, useCallback, useEffect, useState } from "react";
import { createStructuredSelector } from "reselect";
import { useInjectReducer } from "../../../utils/injectReducer";
import { useInjectSaga } from "../../../utils/injectSaga";
import { makeSelectOrders, makeSelectOrdersPagination } from "./selectors";
import { getFoodAdminOrders, setDeliverers } from "./actions";

import reducer from "./reducer";
import saga from "./saga";
import { connect } from "react-redux";
import OrderCard from "../../components/OrderCard";
import { englishNumberToPersianNumber, getQueryParams } from "../../../utils/helper";
import Pagination from "../../components/Pagination";
import CheckBox from "../../components/CheckBox";
import Icon from "../../components/Icon";
import { ICONS } from "../../../assets/images/icons";
import { makeSelectPlugin } from "../../../stores/business/selector";
import { makeSelectLoading } from "../App/selectors";

const AssignDeliverer = function ({
_getAdminOrders,
orders,
pagination,
location,
pluginData,
_setDeliverers,
loading,
history,
}) {
useInjectReducer({ key: "assignDeliverer", reducer });
useInjectSaga({ key: "assignDeliverer", saga });
const [selected, setSelected] = useState([]);
const [sendSms, setSendSms] = useState(true);
const [deliverer, setDeliverer] = useState("");

const page = getQueryParams("page", location.search) || 1;
useEffect(() => {
_getAdminOrders(page);
}, [location]);
useEffect(() => {
setSelected(orders.map(() => false));
}, [orders]);
const deliverers =
pluginData.data && pluginData.data.deliverers ? pluginData.data.deliverers : [];
const assign = useCallback(
(deliverer) => () => {
if (loading) return;
setDeliverer(deliverer);
const orderIds = [];
selected.map((isSelected, index) => {
if (isSelected) return orderIds.push(orders[index].id);
});
if (!orderIds.length) return;
_setDeliverers({
deliverer,
sendSms,
orders: orderIds,
page,
});
},
[selected, sendSms]
);
return (
<div className="d-flex flex-1 mx-5 mt-5" style={{ height: "calc(100% - 180px)" }}>
<div className="u-border-radius-8 u-background-white container px-0 container-shadow overflow-hidden">
<div
className="header-shadow position-relative d-flex py-2 align-items-center px-4"
style={{ marginRight: -10 }}>
<div className="d-flex flex-1 align-items-center">
<Icon icon={ICONS.CONTROL_DOWN} size={25} color="#949C9F" />
<CheckBox
checked={selected.length && selected.every(Boolean)}
onChange={(checked) => setSelected(orders.map(() => checked))}
label={`defaultCheck`}
/>
{selected.some(Boolean) && (
<div className="mr-2 u-fontWeightBold">
{englishNumberToPersianNumber(selected.filter((s) => s === true).length)} سفارش
انتخاب شده ...
</div>
)}
</div>
{selected.some((s, index) => s && orders[index].deliverer_name) && (
<div
onClick={assign("")}
className="d-flex align-items-center u-text-primary-blue u-fontMedium u-cursor-pointer">
<Icon icon={ICONS.TRASH} size={19} color="#168fd5" />
حذف پیک
</div>
)}
</div>
<div className="py-2 overflow-auto px-4" style={{ height: "calc(100% - 90px)" }}>
<div>
{orders.map((order, index) => (
<OrderCard
hasCheck
link="#"
selected={selected[index] || false}
onSelect={() => {
let newSelected = [...selected];
newSelected[index] = !selected[index];
setSelected(newSelected);
}}
isBold={!order.deliverer_name}
key={`order-${order.id}`}
order={order}
/>
))}
</div>
</div>
<Pagination pagination={pagination} location={location} />
</div>
{deliverers.length ? (
<div
className="u-relative u-background-white overflow-auto box-shadow h-100 u-border-radius-8 mr-4"
style={{ width: 395 }}>
<div className="d-flex flex-column flex-1 p-3">
<div className="d-flex align-items-center justify-content-between">
<div className="u-text-black u-fontWeightBold">
<Icon icon={ICONS.DELIVERY} size={24} color="black" className="ml-2" />
پیک‌ها
</div>
<div
className="u-text-primary-blue u-fontWeightBold u-cursor-pointer"
onClick={() => history.push("/delivery/deliveries")}>
لیست تحویل‌ها
<Icon icon={ICONS.CHEVRON} color="#168fd5" size={24} className="mr-1" />
</div>
</div>
{selected.some(Boolean) && (
<div className="u-text-black mt-3">پیک‌ موردنظر را انتخاب کنید...</div>
)}
<div className="u-text-black u-fontMedium mt-3">
<CheckBox
className="u-fontMedium"
label="defaultCheck1"
checked={sendSms}
onChange={setSendSms}
text="آدرس مشتری روی نقشه برای پیک پیامک شود."
/>
</div>
<div className="mt-2">
{deliverers.map((d) => (
<div
className={`d-flex py-2 px-3 u-fontWeightBold u-border-radius-8 u-cursor-pointer ${
loading && deliverer === d.name
? "u-background-primary-blue u-text-white"
: "u-background-melo-grey u-text-darkest-grey"
}`}
style={{ marginTop: 2 }}
onClick={assign(d.name)}
key={`deliverer-${d.name}`}>
<span>{d.name}</span>
</div>
))}
</div>
</div>
</div>
) : null}
</div>
);
};

const mapStateToProps = createStructuredSelector({
orders: makeSelectOrders(),
pluginData: makeSelectPlugin(),
pagination: makeSelectOrdersPagination(),
loading: makeSelectLoading(),
});

function mapDispatchToProps(dispatch) {
return {
_getAdminOrders: (page) => dispatch(getFoodAdminOrders(page)),
_setDeliverers: (data) => dispatch(setDeliverers(data)),
};
}

const withConnect = connect(mapStateToProps, mapDispatchToProps);
export default compose(withConnect, withRouter, memo)(AssignDeliverer);
Loading

0 comments on commit 9c1a84c

Please sign in to comment.