From 32e1b4c3fdf4a61950406dbbaaae4d36d1ef8407 Mon Sep 17 00:00:00 2001
From: muerwre <gotham48@gmail.com>
Date: Mon, 11 Feb 2019 15:36:55 +0700
Subject: [PATCH] basic UI for row editing

---
 backend/routes/auth/check.js             | 18 ++---
 backend/routes/route/list.js             |  4 +-
 src/components/Switch.jsx                |  1 -
 src/components/dialogs/MapListDialog.jsx | 25 ++++++-
 src/components/maps/RouteRow.jsx         | 80 ++++++++++++++--------
 src/components/maps/RouteRowEditor.jsx   | 81 ++++++++++++++++++++++
 src/components/panels/UserPanel.jsx      |  3 -
 src/modules/Editor.js                    |  2 +-
 src/redux/user/sagas.js                  |  4 +-
 src/sprites/icon.svg                     |  2 +-
 src/styles/colors.less                   |  2 +-
 src/styles/dialogs.less                  | 87 ++++++++++++++++++++----
 src/styles/main.less                     |  4 ++
 13 files changed, 248 insertions(+), 65 deletions(-)
 create mode 100644 src/components/maps/RouteRowEditor.jsx

diff --git a/backend/routes/auth/check.js b/backend/routes/auth/check.js
index 858ea73..76c07f3 100644
--- a/backend/routes/auth/check.js
+++ b/backend/routes/auth/check.js
@@ -4,15 +4,15 @@ const { generateGuest, generateRandomUrl } = require('./guest');
 module.exports = async (req, res) => {
   const { id, token } = req.query;
 
-  const user = await User.findOne({ _id: id, token })
-    .populate({
-      path: 'routes',
-      select: '_id title distance owner updated_at',
-      options: {
-        limit: 200,
-        sort: { updated_at: -1 },
-      }
-    });
+  const user = await User.findOne({ _id: id, token });
+  // .populate({
+  //   path: 'routes',
+  //   select: '_id title distance owner updated_at',
+  //   options: {
+  //     limit: 200,
+  //     sort: { updated_at: -1 },
+  //   }
+  // })
 
   const random_url = await generateRandomUrl();
 
diff --git a/backend/routes/route/list.js b/backend/routes/route/list.js
index 423ad95..13c7fab 100644
--- a/backend/routes/route/list.js
+++ b/backend/routes/route/list.js
@@ -32,12 +32,12 @@ module.exports = async (req, res) => {
     {
       ...criteria,
     },
-    '_id title distance owner updated_at',
+    '_id title distance owner updated_at is_public',
     {
       limit: 500,
       sort: { updated_at: -1 },
     }
-  ).populate('owner');
+  ).populate('owner', '_id');
 
   list = list.filter(item => (
     !author || item.owner._id === author
diff --git a/src/components/Switch.jsx b/src/components/Switch.jsx
index 022487b..d65662b 100644
--- a/src/components/Switch.jsx
+++ b/src/components/Switch.jsx
@@ -4,7 +4,6 @@ import classnames from 'classnames';
 
 type Props = {
   active: Boolean,
-
   onPress: Function,
 }
 export const Switch = ({ active, onPress = () => {} }: Props) => (
diff --git a/src/components/dialogs/MapListDialog.jsx b/src/components/dialogs/MapListDialog.jsx
index a28dbee..36047cc 100644
--- a/src/components/dialogs/MapListDialog.jsx
+++ b/src/components/dialogs/MapListDialog.jsx
@@ -28,8 +28,11 @@ type Props = {
       author: String,
       distance: Array<Number>,
       tab: Array<string>,
-    }
+      min: number,
+      max: number,
+    },
   },
+  marks: { [x: number]: string },
   editing: Boolean,
   routes_sorted: Array<string>,
 
@@ -39,7 +42,18 @@ type Props = {
   setDialogActive: Function,
 };
 
-class Component extends React.Component<Props> {
+type State = {
+  editing_item: ?string,
+}
+
+class Component extends React.Component<Props, State> {
+  state = {
+    editing_item: null,
+  };
+
+  startEditing = editing_item => this.setState({ editing_item });
+  stopEditing = () => this.setState({ editing_item: null });
+
   setTitle = ({ target: { value } }) => {
     this.props.searchSetTitle(value);
   };
@@ -67,6 +81,8 @@ class Component extends React.Component<Props> {
       marks,
     } = this.props;
 
+    const { editing_item } = this.state;
+
     return (
       <div className="dialog-content">
         { list.length === 0 && loading &&
@@ -136,9 +152,12 @@ class Component extends React.Component<Props> {
                 <RouteRow
                   editing={editing}
                   {...route}
-                  key={route._id}
                   openRoute={this.openRoute}
                   tab={tab}
+                  is_editing={(editing_item === route._id)}
+                  startEditing={this.startEditing}
+                  stopEditing={this.stopEditing}
+                  key={route._id}
                 />
               ))
             }
diff --git a/src/components/maps/RouteRow.jsx b/src/components/maps/RouteRow.jsx
index bdd1128..340f250 100644
--- a/src/components/maps/RouteRow.jsx
+++ b/src/components/maps/RouteRow.jsx
@@ -1,41 +1,67 @@
 // @flow
 import React from 'react';
 import { Icon } from '$components/panels/Icon';
+import classnames from 'classnames';
+import { RouteRowEditor } from '$components/maps/RouteRowEditor';
 
 type Props = {
-  title: String,
-  distance: Number,
-  created_at: String,
-  _id: String,
-  editing: Boolean,
+  _id: string,
+  title: string,
+  distance: number,
+  tab: string,
+  is_editing: boolean,
+  is_public: boolean,
 
-  openRoute: Function,
+
+  openRoute: (_id: string) => {},
+  startEditing: (_id: string) => {},
+  stopEditing: () => {},
 };
 
 export const RouteRow = ({
-  title, distance, _id, openRoute, tab,
+  title, distance, _id, openRoute, tab, is_editing, startEditing, stopEditing, is_public
 }: Props) => (
-  <div className="route-row-wrapper">
-    <div
-      className="route-row"
-      onClick={() => openRoute(_id)}
-    >
-      <div className="route-row-edit">
+  <div className={classnames('route-row-wrapper', { is_editing })}>
+    {
+      tab === 'mine' &&
+      <div className="route-row-edit" onClick={() => startEditing(_id)}>
         <Icon icon="icon-edit-1" />
       </div>
-      <div className="route-title">
-        {title || _id}
-      </div>
-      <div className="route-description">
-        <span>
-          <Icon icon="icon-link-1" />
-          {_id}
-        </span>
-        <span>
-          <Icon icon="icon-cycle-1" />
-          {(distance && `${distance} km`) || '0 km'}
-        </span>
-      </div>
-    </div>
+    }
+    {
+      !is_editing
+      ?
+        <div
+          className="route-row"
+        >
+          <div onClick={() => openRoute(_id)}>
+            <div className="route-title">
+              <span>{(title || _id)}</span>
+            </div>
+            <div className="route-description">
+              <span>
+                <Icon icon="icon-link-1" />
+                {_id}
+              </span>
+              <span>
+                <Icon icon="icon-cycle-1" />
+                {(distance && `${distance} km`) || '0 km'}
+              </span>
+            </div>
+          </div>
+          <div className="route-row-panel">
+            <div className="">
+              <Icon icon="icon-trash-4" size={24} />
+              Удалить
+            </div>
+            <div className="flex_1 justify-end" onClick={() => startEditing(_id)}>
+              <Icon icon="icon-edit-1" size={24} />
+              Правка
+            </div>
+          </div>
+        </div>
+      : <RouteRowEditor title={title} is_public={is_public} distance={distance} _id={_id} />
+    }
+
   </div>
 );
diff --git a/src/components/maps/RouteRowEditor.jsx b/src/components/maps/RouteRowEditor.jsx
new file mode 100644
index 0000000..9f2d7d7
--- /dev/null
+++ b/src/components/maps/RouteRowEditor.jsx
@@ -0,0 +1,81 @@
+// @flow
+import React from 'react';
+import { Icon } from '$components/panels/Icon';
+import { Switch } from '$components/Switch';
+
+type Props = {
+  title: string,
+  is_public: boolean,
+  distance: number,
+  _id: string,
+};
+
+type State = {
+  title: string,
+  is_public: boolean,
+};
+
+export class RouteRowEditor extends React.PureComponent<Props, State> {
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      title: props.title,
+      is_public: props.is_public,
+    };
+  }
+
+  stopEditing = () => console.log();
+  setPublic = () => this.setState({ is_public: !this.state.is_public });
+  setTitle = ({ target: { value } }: { target: { value: string } }) => this.setState({ title: value });
+
+  render() {
+    const {
+      state: { title, is_public },
+      props: { distance, _id }
+    } = this;
+
+    return (
+      <div
+        className="route-row"
+      >
+        <div className="route-title">
+          <input
+            type="text"
+            value={title}
+            onChange={this.setTitle}
+            placeholder="Введите название"
+            autoFocus
+          />
+        </div>
+        <div className="route-description">
+          <span>
+            <Icon icon="icon-link-1" />
+            {_id}
+          </span>
+          <span>
+            <Icon icon="icon-cycle-1" />
+            {(distance && `${distance} km`) || '0 km'}
+          </span>
+        </div>
+        <div className="route-row-editor">
+          <div className="route-row-buttons">
+            <div className="flex_1" onClick={this.setPublic}>
+              <Switch
+                active={is_public}
+              />
+              {
+                is_public
+                  ? ' В каталоге карт'
+                  : ' Только по ссылке'
+              }
+            </div>
+            <div className="button primary" onClick={this.stopEditing}>
+              OK
+            </div>
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/src/components/panels/UserPanel.jsx b/src/components/panels/UserPanel.jsx
index 06e6e1c..6905ce6 100644
--- a/src/components/panels/UserPanel.jsx
+++ b/src/components/panels/UserPanel.jsx
@@ -92,8 +92,6 @@ export class Component extends React.PureComponent<Props, void> {
       state: { menuOpened },
     } = this;
 
-    const route_count = Object.keys(user.routes).length;
-
     return (
       <div>
         <div className="panel active panel-user">
@@ -114,7 +112,6 @@ export class Component extends React.PureComponent<Props, void> {
           <div className="control-bar">
             <button
               className={classnames({
-                disabled: route_count <= 0,
                 active: dialog_active && (dialog === DIALOGS.MAP_LIST)
               })}
               onClick={this.openMapsDialog}
diff --git a/src/modules/Editor.js b/src/modules/Editor.js
index 21bcc8b..65cddd9 100644
--- a/src/modules/Editor.js
+++ b/src/modules/Editor.js
@@ -228,7 +228,7 @@ export class Editor {
   };
 
   setData = ({
-    route = [], stickers = [], owner, title, address, provider = DEFAULT_PROVIDER, logo = DEFAULT_LOGO, public: is_public,
+    route = [], stickers = [], owner, title, address, provider = DEFAULT_PROVIDER, logo = DEFAULT_LOGO, is_public,
   }) => {
     this.setTitle(title || '');
     const { id } = this.getUser();
diff --git a/src/redux/user/sagas.js b/src/redux/user/sagas.js
index 7a622b9..718d788 100644
--- a/src/redux/user/sagas.js
+++ b/src/redux/user/sagas.js
@@ -17,7 +17,7 @@ import {
   setSaveError,
   setSaveOverwrite, setSaveSuccess, setTitle,
   searchSetTab,
-  setUser, setDialog, setPublic, setAddressOrigin, setProvider, changeProvider,
+  setUser, setDialog, setPublic, setAddressOrigin, setProvider, changeProvider, openMapDialog,
 } from '$redux/user/actions';
 import { getUrlData, parseQuery, pushLoaderState, pushNetworkInitError, pushPath, replacePath } from '$utils/history';
 import { editor } from '$modules/Editor';
@@ -70,8 +70,6 @@ function* startEmptyEditorSaga() {
 }
 
 function* startEditingSaga() {
-  // yield put(setEditing(true));
-  // yield editor.startEditing();
   const { path } = getUrlData();
   yield pushPath(`/${path}/edit`);
 }
diff --git a/src/sprites/icon.svg b/src/sprites/icon.svg
index 604873a..6e38daa 100644
--- a/src/sprites/icon.svg
+++ b/src/sprites/icon.svg
@@ -375,5 +375,5 @@
         </svg>
     </defs>
 
-    <use xlink:href="#icon-edit-1" />
+    <use xlink:href="#icon-sad-1" />
 </svg>
diff --git a/src/styles/colors.less b/src/styles/colors.less
index 03de625..f06ba7a 100644
--- a/src/styles/colors.less
+++ b/src/styles/colors.less
@@ -4,7 +4,7 @@
 @router_line: #4597d0;
 
 @bar_background: #333333;
-@dialog_background: #222222;
+@dialog_background: #271535;
 
 @location_line: #ff3344;
 
diff --git a/src/styles/dialogs.less b/src/styles/dialogs.less
index 7f71e5e..3217deb 100644
--- a/src/styles/dialogs.less
+++ b/src/styles/dialogs.less
@@ -71,7 +71,7 @@
 }
 
 .dialog-content {
-  background: #271535;
+  background: @dialog_background;
   height: 100%;
   overflow: hidden;
   position: relative;
@@ -163,21 +163,40 @@
 }
 
 .route-row-wrapper {
-  overflow: hidden;
   padding: 0 10px;
+  position: relative;
+  margin-bottom: 10px;
+  transition: all 500ms;
 
-  &:hover {
-    .route-row {
-      transform: translateX(-48px);
-    }
-    .route-row-edit {
-      opacity: 1;
-    }
+  //&:hover {
+  //  .route-row { transform: translateX(-58px); }
+  //  .route-row-edit { transform: translateX(-58px); }
+  //
+  //  &.is_editing {
+  //    .route-row { transform: translateX(0); }
+  //    .route-row-edit { transform: translateX(0); }
+  //  }
+  //}
+
+  &.is_editing {
+    //transform: translateY(-2px);
+    .route-row { background: rgba(255, 100, 100, 0.2); }
   }
 }
 
+.route-row-editor {
+  color: white;
+  padding: 20px 0 5px;
+}
+
+.route-row-buttons {
+  flex: 1;
+  flex-direction: row;
+  display: flex;
+  align-items: center;
+}
+
 .route-row {
-  margin-bottom: 10px;
   background: rgba(255, 255, 255, 0.05);
   padding: 10px 10px 5px 10px;
   color: white;
@@ -188,23 +207,63 @@
 
   &:hover {
     background: rgba(255, 255, 255, 0.1);
+
+    .route-row-panel {
+      transform: scaleY(1);
+      pointer-events: all;
+      touch-action: initial;
+    }
+  }
+}
+
+.route-row-panel {
+  position: absolute;
+  top: 100%;
+  height: 32px;
+  width: 100%;
+  left: 0;
+  background: mix(@dialog_background, white, 80%);
+  border-radius: 0 0 @panel_radius @panel_radius;
+  z-index: 1;
+  transform: scaleY(0);
+  pointer-events: none;
+  touch-action: none;
+  transition: transform 250ms;
+  transform-origin: 0 0;
+  padding: 0 5px;
+  box-sizing: border-box;
+  display: flex;
+  align-items: center;
+  fill: white;
+
+  & > div {
+    display: flex;
+    align-items: center;
+
+    svg {
+      margin-right: 2px;
+    }
   }
 }
 
 .route-row-edit {
-  fill: rgba(0, 0, 0, 0.5);
-  left: 100%;
+  fill: rgba(255, 255, 255, 0.3);
+  right: -48px;
+  padding-left: 0px;
   stroke: none;
   position: absolute;
   top: 0;
   width: 58px;
-  background: rgba(255, 255, 255, 0.2);
   height: 100%;
-  opacity: 0;
   transition: all 500ms;
   display: flex;
   align-items: center;
   justify-content: center;
+  cursor: pointer;
+
+  &:hover {
+    fill: @green_secondary;
+  }
 }
 
 .route-title {
diff --git a/src/styles/main.less b/src/styles/main.less
index eb8364a..f521dd8 100644
--- a/src/styles/main.less
+++ b/src/styles/main.less
@@ -153,3 +153,7 @@ input {
 .relative {
   position: relative;
 }
+
+.justify-end {
+  justify-content: flex-end;
+}