From 037575409dec21afd7873f114f7a303af6a07174 Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Wed, 7 Mar 2018 21:10:48 -0500 Subject: [PATCH 01/23] fix request access notif page --- src/routes/Notifications/NotificationPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/Notifications/NotificationPage.js b/src/routes/Notifications/NotificationPage.js index 18debfe3..f85ab89f 100644 --- a/src/routes/Notifications/NotificationPage.js +++ b/src/routes/Notifications/NotificationPage.js @@ -34,7 +34,7 @@ class NotificationPage extends Component { const request = notification.data.object const map = notification.data.map const subject = notification.type === MAP_ACCESS_REQUEST ? - ({request.user.name} wants to collaborate on map { map.name }) + ({notification.actor.name} wants to collaborate on map { map.name }) : notification.subject return (
@@ -62,7 +62,7 @@ class NotificationPage extends Component {

Go to map    - View mapper profile + View mapper profile
} {notification.type !== MAP_ACCESS_REQUEST && } From 2971b81463395557518999bcde0341a3232d1cf6 Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Wed, 7 Mar 2018 21:16:03 -0500 Subject: [PATCH 02/23] convert a tags to link tags in mobile menu --- src/components/MobileHeader.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/components/MobileHeader.js b/src/components/MobileHeader.js index dd27c2a7..541f014c 100644 --- a/src/components/MobileHeader.js +++ b/src/components/MobileHeader.js @@ -44,11 +44,11 @@ class MobileHeader extends Component {
  • - + New Map - +
  • @@ -79,34 +79,34 @@ class MobileHeader extends Component {
  • - + Account - +
  • - + Notifications - + {unreadNotificationsCount > 0 &&
    }
  • - + Sign Out - +
  • } {!currentUser && } } From c1dbfc9f7285600c8c97fb1bb17c3047a1392c79 Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Thu, 8 Mar 2018 07:25:54 -0500 Subject: [PATCH 03/23] add unreadnotificationscount --- sass/notifications.scss | 106 +++++++++++----------- src/Metamaps/GlobalUI/Notifications.js | 2 +- src/components/NotificationBox.js | 4 +- src/routes/Notifications/Notifications.js | 2 +- 4 files changed, 55 insertions(+), 59 deletions(-) diff --git a/sass/notifications.scss b/sass/notifications.scss index 4c97547b..3cec306b 100644 --- a/sass/notifications.scss +++ b/sass/notifications.scss @@ -81,67 +81,63 @@ $unread_notifications_dot_size: 8px; } } -.controller-notifications { - .notificationPage, - .notificationsPage { - font-family: 'din-regular', Sans-Serif; +.notificationPage, +.notificationsPage { + font-family: 'din-regular', Sans-Serif; - & a:hover { - text-decoration: none; + & a:hover { + text-decoration: none; + } + + & > .notification-title { + border-bottom: 1px solid #eee; + padding-bottom: 0.25em; + margin-bottom: 0.5em; + } + + .back { + margin-top: 1em; + } +} + +.notificationsPage { + header { + margin-bottom: 0; + } + + .emptyInbox { + padding-top: 15px; + } +} + +.notificationPage { + .thirty-two-avatar { + display: inline-block; + width: 32px; + height: 32px; + border-radius: 16px; + vertical-align: middle; + } + + .button { + line-height: 32px; + + img { + margin-top: 8px; } - & > .notification-title { - border-bottom: 1px solid #eee; - padding-bottom: 0.25em; - margin-bottom: 0.5em; - } - - .back { - margin-top: 1em; + &.decline { + background: #DB5D5D; + &:hover { + background: #DC4B4B; + } } } - .notificationsPage { - header { - margin-bottom: 0; - } - - .emptyInbox { - padding-top: 15px; - } - } - - - - .notificationPage { - .thirty-two-avatar { - display: inline-block; - width: 32px; - height: 32px; - border-radius: 16px; - vertical-align: middle; - } - - .button { - line-height: 32px; - - img { - margin-top: 8px; - } - - &.decline { - background: #DB5D5D; - &:hover { - background: #DC4B4B; - } - } - } - - .notification-body { - p, div { - margin: 1em auto; - line-height: 20px; - } + .notification-body { + p, div { + margin: 1em auto; + line-height: 20px; } } } diff --git a/src/Metamaps/GlobalUI/Notifications.js b/src/Metamaps/GlobalUI/Notifications.js index 2ed7238d..1b93d2cd 100644 --- a/src/Metamaps/GlobalUI/Notifications.js +++ b/src/Metamaps/GlobalUI/Notifications.js @@ -7,7 +7,7 @@ const Notifications = { notificationsLoading: false, unreadNotificationsCount: 0, init: serverData => { - Notifications.unreadNotificationsCount = serverData.unreadNotificationsCount + Notifications.unreadNotificationsCount = serverData.ActiveMapper.unread_notifications_count }, fetchNotifications: render => { Notifications.notificationsLoading = true diff --git a/src/components/NotificationBox.js b/src/components/NotificationBox.js index fdb836f6..b3669de4 100644 --- a/src/components/NotificationBox.js +++ b/src/components/NotificationBox.js @@ -61,11 +61,11 @@ class NotificationBox extends Component { } render = () => { - const { loading } = this.props + const { notifications, loading } = this.props return
      - {loading ? this.showLoading() : this.showNotifications()} + {notifications.length === 0 && loading ? this.showLoading() : this.showNotifications()}
    } diff --git a/src/routes/Notifications/Notifications.js b/src/routes/Notifications/Notifications.js index a1f96cfd..bfe92b75 100644 --- a/src/routes/Notifications/Notifications.js +++ b/src/routes/Notifications/Notifications.js @@ -27,7 +27,7 @@ class Notifications extends Component { render = () => { const { notificationsLoading, markAsRead, markAsUnread } = this.props const notifications = (this.props.notifications || []).filter(n => !(BLACKLIST.indexOf(n.type) > -1 && (!n.data.object || !n.data.map))) - if (notificationsLoading) { + if (notifications.length === 0 && notificationsLoading) { return (
    From 6c84205b38284724f7bac7c2ba2fbfb0ea3f6071 Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Thu, 8 Mar 2018 07:26:04 -0500 Subject: [PATCH 04/23] move lightboxes into react --- README.md | 9 +- public/index.html | 550 ++++++++----------- src/components/LightBoxes/About.js | 64 +++ src/components/LightBoxes/CheatSheet.js | 163 ++++++ src/components/LightBoxes/ForkMap.js | 12 + src/components/LightBoxes/Invite.js | 23 + src/components/LightBoxes/NoIE.js | 22 + src/components/LightBoxes/SwitchMetacodes.js | 12 + src/components/LightBoxes/Tutorial.js | 14 + src/components/LightBoxes/index.js | 33 ++ src/routes/App.js | 2 + 11 files changed, 570 insertions(+), 334 deletions(-) create mode 100644 src/components/LightBoxes/About.js create mode 100644 src/components/LightBoxes/CheatSheet.js create mode 100644 src/components/LightBoxes/ForkMap.js create mode 100644 src/components/LightBoxes/Invite.js create mode 100644 src/components/LightBoxes/NoIE.js create mode 100644 src/components/LightBoxes/SwitchMetacodes.js create mode 100644 src/components/LightBoxes/Tutorial.js create mode 100644 src/components/LightBoxes/index.js diff --git a/README.md b/README.md index c84c65d3..38401cd9 100644 --- a/README.md +++ b/README.md @@ -26,13 +26,16 @@ Checklist - [x] Fix images referenced in the JS - [x] Figure out how authentication of requests from the frontend to the API works - [x] Figure out how to combine the nodejs realtime server into server.js -- [ ] Notifications: make sure loading states are working for popup and page +- [x] Notifications: make sure loading states are working for popup and page - [ ] Notifications: make sure notifications either look nice, or redirect - [ ] Notifications: pagination - [ ] Get actioncable working -- [ ] Request unreadNotificationCount -- [ ] Request invite code +- [ ] lightboxes +- [x] Request unreadNotificationCount +- [x] Request invite code - [x] Request user object itself +- [ ] About lightbox +- [ ] break up index.html into parts - [ ] Handle CSS metacode colors - [ ] Fix Request An Invite page - [ ] Make 'new map' action work diff --git a/public/index.html b/public/index.html index a0b79386..f7496952 100644 --- a/public/index.html +++ b/public/index.html @@ -11,17 +11,18 @@ + - - - - Metamaps + + + + Metamaps - + - + - + - + + -
    -
    -
    -
    - - - - - - - - - - - - - - - - - - - + +
    + -
    - - - - - - - - - - - - - +
    +
    + - } } From 150e7a4dfb3cdb86346ba321c9bf7e1465a33e4d Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Thu, 8 Mar 2018 09:46:05 -0500 Subject: [PATCH 05/23] newsynapse newtopic and allow/decline access --- README.md | 17 ++-- sass/notifications.scss | 6 ++ src/Metamaps/Create.js | 2 - src/Metamaps/DataFetcher.js | 22 +++++- src/Metamaps/GlobalUI/Notifications.js | 4 +- src/Metamaps/GlobalUI/ReactApp.js | 11 ++- src/components/LightBoxes/CheatSheet.js | 8 +- src/components/NewSynapse.js | 18 +++++ src/components/NewTopic.js | 44 +++++++++++ src/routes/MapView/index.js | 6 +- src/routes/Notifications/NotificationPage.js | 81 ++++++++++++++++---- 11 files changed, 186 insertions(+), 33 deletions(-) create mode 100644 src/components/NewSynapse.js create mode 100644 src/components/NewTopic.js diff --git a/README.md b/README.md index 38401cd9..8d3ad916 100644 --- a/README.md +++ b/README.md @@ -27,14 +27,21 @@ Checklist - [x] Figure out how authentication of requests from the frontend to the API works - [x] Figure out how to combine the nodejs realtime server into server.js - [x] Notifications: make sure loading states are working for popup and page +- [x] Request unreadNotificationCount +- [x] Request invite code +- [x] Request user object itself +- [x] Load the metacodes + +- [ ] create topic form +- [ ] create synapse form +- [ ] move ImportDialog lightbox into main app - [ ] Notifications: make sure notifications either look nice, or redirect - [ ] Notifications: pagination - [ ] Get actioncable working - [ ] lightboxes -- [x] Request unreadNotificationCount -- [x] Request invite code -- [x] Request user object itself - [ ] About lightbox +- [ ] Switch Metacodes lightbox / component +- [ ] Fork map lightbox / component - [ ] break up index.html into parts - [ ] Handle CSS metacode colors - [ ] Fix Request An Invite page @@ -53,7 +60,5 @@ Checklist - [ ] authorize - [ ] user passwords - [ ] Modify the RubyOnRails app to only serve JSON responses, no HTML pages anymore -- [ ] Modify the RubyOnRails app to include an endpoint that responds with basic data the front end needs to display (such as the invite code for the user, and the current metamaps build) (a bunch of the data found here: https://github.com/metamaps/metamaps/blob/frontendonly/Metamaps.ServerData.js.erb) - [ ] Modify the frontend to request that data from the API which is necessary at first to load the page -- [x] Load the metacodes -- [ ] Load the metacode sets + - [ ] Load the metacode sets diff --git a/sass/notifications.scss b/sass/notifications.scss index 3cec306b..777d724e 100644 --- a/sass/notifications.scss +++ b/sass/notifications.scss @@ -117,6 +117,7 @@ $unread_notifications_dot_size: 8px; height: 32px; border-radius: 16px; vertical-align: middle; + margin-right: 8px; } .button { @@ -127,6 +128,7 @@ $unread_notifications_dot_size: 8px; } &.decline { + margin-left: 8px; background: #DB5D5D; &:hover { background: #DC4B4B; @@ -139,6 +141,10 @@ $unread_notifications_dot_size: 8px; margin: 1em auto; line-height: 20px; } + + .accessRequestError { + color: #DB5D5D; + } } } diff --git a/src/Metamaps/Create.js b/src/Metamaps/Create.js index 454ab331..b18d71cc 100644 --- a/src/Metamaps/Create.js +++ b/src/Metamaps/Create.js @@ -19,8 +19,6 @@ const Create = { newSelectedMetacodes: [], init: function() { var self = Create - self.newTopic.init() - self.newSynapse.init() // // SWITCHING METACODE SETS diff --git a/src/Metamaps/DataFetcher.js b/src/Metamaps/DataFetcher.js index 3bea2f2c..7a9f2fae 100644 --- a/src/Metamaps/DataFetcher.js +++ b/src/Metamaps/DataFetcher.js @@ -2,6 +2,14 @@ function fetchWithCookies(url) { return fetch(url, { credentials: 'same-origin' }) } +function postWithCookies(url, data = {}) { + return fetch(url, { + credentials: 'same-origin', + method: 'POST', + body: JSON.stringify(data) + }) +} + async function getMetacodes() { const res = await fetchWithCookies('/metacodes.json') const data = await res.json() @@ -14,7 +22,19 @@ async function getCurrentUser() { return data } +async function approveAccessRequest(mapId, requestId) { + const res = await postWithCookies(`/maps/${mapId}/approve_access/${requestId}`) + return res.status === 200 +} + +async function denyAccessRequest(mapId, requestId) { + const res = await postWithCookies(`/maps/${mapId}/deny_access/${requestId}`) + return res.status === 200 +} + module.exports = { getMetacodes, - getCurrentUser + getCurrentUser, + approveAccessRequest, + denyAccessRequest } \ No newline at end of file diff --git a/src/Metamaps/GlobalUI/Notifications.js b/src/Metamaps/GlobalUI/Notifications.js index 1b93d2cd..0ab962a8 100644 --- a/src/Metamaps/GlobalUI/Notifications.js +++ b/src/Metamaps/GlobalUI/Notifications.js @@ -7,7 +7,9 @@ const Notifications = { notificationsLoading: false, unreadNotificationsCount: 0, init: serverData => { - Notifications.unreadNotificationsCount = serverData.ActiveMapper.unread_notifications_count + if (serverData.ActiveMapper) { + Notifications.unreadNotificationsCount = serverData.ActiveMapper.unread_notifications_count + } }, fetchNotifications: render => { Notifications.notificationsLoading = true diff --git a/src/Metamaps/GlobalUI/ReactApp.js b/src/Metamaps/GlobalUI/ReactApp.js index cb5dc947..08752098 100644 --- a/src/Metamaps/GlobalUI/ReactApp.js +++ b/src/Metamaps/GlobalUI/ReactApp.js @@ -10,7 +10,9 @@ import { notifyUser } from './index.js' import ImportDialog from './ImportDialog' import Notifications from './Notifications' import Active from '../Active' +import Create from '../Create' import DataModel from '../DataModel' +import DataFetcher from '../DataFetcher' import { ExploreMaps, ChatView, TopicCard, ContextMenu } from '../Views' import Filter from '../Filter' import JIT from '../JIT' @@ -107,7 +109,9 @@ const ReactApp = { fetchNotifications: apply(Notifications.fetchNotifications, ReactApp.render), fetchNotification: apply(Notifications.fetchNotification, ReactApp.render), markAsRead: apply(Notifications.markAsRead, ReactApp.render), - markAsUnread: apply(Notifications.markAsUnread, ReactApp.render) + markAsUnread: apply(Notifications.markAsUnread, ReactApp.render), + denyAccessRequest: DataFetcher.denyAccessRequest, + approveAccessRequest: DataFetcher.approveAccessRequest }, self.getMapProps(), self.getTopicProps(), @@ -134,9 +138,12 @@ const ReactApp = { toggleMapInfoBox: InfoBox.toggleBox, infoBoxHtml: InfoBox.html, openImportLightbox: () => ImportDialog.show(), + openMetacodeSwitcher: () => self.openLightbox('metacodeSwitcher'), forkMap: Map.fork, onMapStar: Map.star, - onMapUnstar: Map.unstar + onMapUnstar: Map.unstar, + initNewTopic: Create.newTopic.init, + initNewSynapse: Create.newSynapse.init } }, getCommonProps: function() { diff --git a/src/components/LightBoxes/CheatSheet.js b/src/components/LightBoxes/CheatSheet.js index c82a1504..ade782fe 100644 --- a/src/components/LightBoxes/CheatSheet.js +++ b/src/components/LightBoxes/CheatSheet.js @@ -3,7 +3,7 @@ import React, { Component } from 'react' class CheatSheet extends Component { render = () => { return ( -
    +

    HELP

    -
    Enter Topic (radial) View: Click on a Topic result from Search, or click the synapse icon inside open Topic Card on map
    +
    Enter Topic (radial) View: Click on a Topic result from Search, or click the synapse icon inside open Topic Card on map
    Recenter Topics around chosen Topic: Alt + click on the topic OR Alt + E
    Reveal the siblings for a Topic: Right-click and choose 'Reveal siblings' OR Alt + R
    Center topic and reveal siblings: Alt + T
    @@ -60,7 +60,7 @@ class CheatSheet extends Component { Change Topic permission: Click on 'Permission' icon (only for topic creator)
    - Open Topic view: Click on icon within topic card bar + Open Topic view: Click on icon within topic card bar
    Close Topic card: Click on canvas @@ -131,7 +131,7 @@ class CheatSheet extends Component {
    - +

    For more information about Metamaps.cc, visit our Knowledge Base or skip directly to a section by clicking on one of the categories below.

    diff --git a/src/components/NewSynapse.js b/src/components/NewSynapse.js new file mode 100644 index 00000000..10e926f8 --- /dev/null +++ b/src/components/NewSynapse.js @@ -0,0 +1,18 @@ +import React, { Component } from 'react' + +class NewSynapse extends Component { + componentDidMount() { + this.props.initNewSynapse() + } + + render = () => { + return ( +
    + + +
    + ) + } +} + +export default NewSynapse \ No newline at end of file diff --git a/src/components/NewTopic.js b/src/components/NewTopic.js new file mode 100644 index 00000000..3e33af27 --- /dev/null +++ b/src/components/NewTopic.js @@ -0,0 +1,44 @@ +import React, { Component } from 'react' + +class NewTopic extends Component { + componentDidMount() { + this.props.initNewTopic() + } + + render = () => { + const metacodes = [ + { + "id": 1, + "name": "Action", + "created_at": "2017-03-04T17:33:07.394Z", + "updated_at": "2017-03-04T17:33:07.394Z", + "color": "#BD6C85", + "icon": "https://s3.amazonaws.com/metamaps-assets/metacodes/blueprint/96px/bp_action.png" + } + ] + return ( +
    + +
    this.props.openMetacodeSwitcher()}> +
    Switch Metacodes
    +
    + +
    +
    Pin Open
    +
    Unpin
    +
    + +
    + {metacodes.map(m => {m.name})} +
    + + + +
    +
    +
    + ) + } +} + +export default NewTopic \ No newline at end of file diff --git a/src/routes/MapView/index.js b/src/routes/MapView/index.js index 027b395d..64a1a05e 100644 --- a/src/routes/MapView/index.js +++ b/src/routes/MapView/index.js @@ -9,6 +9,8 @@ import Instructions from './Instructions' import VisualizationControls from '../../components/VisualizationControls' import MapChat from './MapChat' import TopicCard from '../../components/TopicCard' +import NewTopic from '../../components/NewTopic' +import NewSynapse from '../../components/NewSynapse' export default class MapView extends Component { @@ -82,7 +84,7 @@ export default class MapView extends Component { openImportLightbox, forkMap, openHelpLightbox, mapIsStarred, onMapStar, onMapUnstar, openTopic, onZoomExtents, onZoomIn, onZoomOut, hasLearnedTopicCreation, - contextMenu } = this.props + contextMenu, initNewTopic, initNewSynapse, openMetacodeSwitcher } = this.props const { chatOpen } = this.state const onChatOpen = () => { this.setState({chatOpen: true}) @@ -111,6 +113,8 @@ export default class MapView extends Component { filterAllMappers={filterAllMappers} filterAllSynapses={filterAllSynapses} /> + + {openTopic && } {contextMenu && } {currentUser && } diff --git a/src/routes/Notifications/NotificationPage.js b/src/routes/Notifications/NotificationPage.js index f85ab89f..8df550c4 100644 --- a/src/routes/Notifications/NotificationPage.js +++ b/src/routes/Notifications/NotificationPage.js @@ -7,12 +7,18 @@ import LoadingPage from '../helpers/LoadingPage' import Loading from '../../components/Loading' import NotificationBody from '../../components/NotificationBody' -/* TODO: - allow / decline access loading states - make backend serve HTML for raw body too -*/ - class NotificationPage extends Component { + constructor(props) { + super(props) + this.state = { + allowPending: false, + declinePending: false, + allowed: false, + declined: false, + error: false + } + } + componentDidMount() { // the notification id const id = parseInt(this.props.params.id, 10) @@ -20,6 +26,35 @@ class NotificationPage extends Component { this.props.fetchNotification(id) } } + + deny = async () => { + const id = parseInt(this.props.params.id, 10) + const notification = this.props.notifications.find(n => n.id === id) + const request = notification.data.object + const map = notification.data.map + this.setState({ declinePending: true }) + const success = await this.props.denyAccessRequest(map.id, request.id) + if (success) { + this.setState({ declined: true, declinePending: false }) + } else { + this.setState({ error: true }) + } + } + + approve = async () => { + const id = parseInt(this.props.params.id, 10) + const notification = this.props.notifications.find(n => n.id === id) + const request = notification.data.object + const map = notification.data.map + this.setState({ allowPending: true }) + const success = await this.props.approveAccessRequest(map.id, request.id) + if (success) { + this.setState({ allowed: true, allowPending: false }) + } else { + this.setState({ error: true }) + } + } + render = () => { const id = parseInt(this.props.params.id, 10) const notification = this.props.notifications.find(n => n.id === id) @@ -36,6 +71,7 @@ class NotificationPage extends Component { const subject = notification.type === MAP_ACCESS_REQUEST ? ({notification.actor.name} wants to collaborate on map { map.name }) : notification.subject + const localAnswered = this.state.allowed || this.state.declined return (
    @@ -48,21 +84,34 @@ class NotificationPage extends Component { {subject} {notification.type === MAP_ACCESS_REQUEST &&
    -

    - {request.answered && +

    + {this.state.error &&
    There was an error, please refresh and try again
    } + {request.answered &&
    {request.approved && You already responded to this access request, and allowed access.} {!request.approved && You already responded to this access request, and declined access. If you changed your mind, you can still grant them access by going to the map and adding them as a collaborator.} - } - {!request.answered && +
    } + {!localAnswered && !request.answered &&
    - Allow - Decline - } -

    - Go to map -    - View mapper profile + {!this.state.declined && !this.state.declinePending && } + {!this.state.allowed && !this.state.allowPending && } +
    } + {this.state.allowed &&
    + {notification.actor.name} has been shared on the map and notified. +
    } + {this.state.declined &&
    + Fair enough. +
    } +
    +
    + Go to map +    + View mapper profile +
    } {notification.type !== MAP_ACCESS_REQUEST && }
    From ceb2420b8d2d723d5d3f6053aaff5ee22c9cea93 Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Thu, 8 Mar 2018 10:08:38 -0500 Subject: [PATCH 06/23] setup invite code/link --- src/Metamaps/GlobalUI/index.js | 15 --- src/components/LightBoxes/Invite.js | 37 +++++- src/components/LightBoxes/index.js | 2 +- src/routes/App.js | 2 +- src/routes/Notifications/NotificationPage.js | 12 +- views/layouts/_lightboxes.js | 113 ------------------- 6 files changed, 38 insertions(+), 143 deletions(-) delete mode 100644 views/layouts/_lightboxes.js diff --git a/src/Metamaps/GlobalUI/index.js b/src/Metamaps/GlobalUI/index.js index 7a7d2ae5..9422bbed 100644 --- a/src/Metamaps/GlobalUI/index.js +++ b/src/Metamaps/GlobalUI/index.js @@ -1,7 +1,5 @@ /* global $ */ -import clipboard from 'clipboard-js' - import Create from '../Create' import Notifications from './Notifications' @@ -137,19 +135,6 @@ const GlobalUI = { ReactApp.render() self.notifying = false } - }, - shareInvite: function(inviteLink) { - clipboard.copy({ - 'text/plain': inviteLink - }).then(() => { - $('#joinCodesBox .popup').remove() - $('#joinCodesBox').append('') - window.setTimeout(() => $('#joinCodesBox .popup').remove(), 1500) - }, () => { - $('#joinCodesBox .popup').remove() - $('#joinCodesBox').append(``) - window.setTimeout(() => $('#joinCodesBox .popup').remove(), 1500) - }) } } diff --git a/src/components/LightBoxes/Invite.js b/src/components/LightBoxes/Invite.js index 53689e74..6ccbf833 100644 --- a/src/components/LightBoxes/Invite.js +++ b/src/components/LightBoxes/Invite.js @@ -1,7 +1,36 @@ import React, { Component } from 'react' +import clipboard from 'clipboard-js' class Invite extends Component { + constructor(props) { + super(props) + this.state = { + copied: false, + unable: false + } + } + + inviteLink = () => { + const { host, protocol } = window ? window.location : {} + const inviteLink = `${protocol}//${host}/join?code=${this.props.inviteCode}` + return inviteLink + } + + shareInvite = () => { + const inviteLink = this.inviteLink() + clipboard.copy({ + 'text/plain': inviteLink + }).then(() => { + this.setState({ copied: true }) + window.setTimeout(() => this.setState({ copied: false }), 1500) + }, () => { + this.setState({ unable: true }) + window.setTimeout(() => this.setState({ unable: false }), 1500) + }) + } + render = () => { + const inviteLink = this.inviteLink() return (

    SHARE INVITE

    @@ -11,8 +40,12 @@ class Invite extends Component {

    Below is a personal invite link containing your unique access code, which can be used multiple times.

    - {`/join?code=${this.props.inviteCode}`} - + {inviteLink} + +

    +

    + {this.state.copied && 'Copied!'} + {this.state.unable && "Your browser doesn't support copying, please copy manually."}

    diff --git a/src/components/LightBoxes/index.js b/src/components/LightBoxes/index.js index fe336376..f851108f 100644 --- a/src/components/LightBoxes/index.js +++ b/src/components/LightBoxes/index.js @@ -18,7 +18,7 @@ class LightBoxes extends Component { - + diff --git a/src/routes/App.js b/src/routes/App.js index 81bd4826..bca42023 100644 --- a/src/routes/App.js +++ b/src/routes/App.js @@ -73,7 +73,7 @@ class App extends Component { signInPage={pathname === '/login'} />} {children} - +
    } } diff --git a/src/routes/Notifications/NotificationPage.js b/src/routes/Notifications/NotificationPage.js index 8df550c4..4f8a1706 100644 --- a/src/routes/Notifications/NotificationPage.js +++ b/src/routes/Notifications/NotificationPage.js @@ -122,14 +122,4 @@ class NotificationPage extends Component { } } -export default NotificationPage - -/* - - */ \ No newline at end of file +export default NotificationPage \ No newline at end of file diff --git a/views/layouts/_lightboxes.js b/views/layouts/_lightboxes.js deleted file mode 100644 index 7c823778..00000000 --- a/views/layouts/_lightboxes.js +++ /dev/null @@ -1,113 +0,0 @@ - - From 3d985b62050e824cc73bcc0bb25d9f805fb8955c Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Thu, 8 Mar 2018 10:22:11 -0500 Subject: [PATCH 07/23] refactor out the cheatsheet file --- README.md | 2 +- src/Metamaps/GlobalUI/index.js | 5 +++++ src/Metamaps/Map/CheatSheet.js | 12 ------------ src/Metamaps/Map/index.js | 2 -- src/Metamaps/index.js | 3 +-- 5 files changed, 7 insertions(+), 17 deletions(-) delete mode 100644 src/Metamaps/Map/CheatSheet.js diff --git a/README.md b/README.md index 8d3ad916..bf5f7e1c 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Checklist - [x] Request user object itself - [x] Load the metacodes -- [ ] create topic form +- [x] create topic form - [ ] create synapse form - [ ] move ImportDialog lightbox into main app - [ ] Notifications: make sure notifications either look nice, or redirect diff --git a/src/Metamaps/GlobalUI/index.js b/src/Metamaps/GlobalUI/index.js index 9422bbed..827e3307 100644 --- a/src/Metamaps/GlobalUI/index.js +++ b/src/Metamaps/GlobalUI/index.js @@ -32,6 +32,11 @@ const GlobalUI = { }) $('#lightbox_screen, #lightbox_close').click(self.closeLightbox) + + // tab the cheatsheet + $('#cheatSheet').tabs() + $('#quickReference').tabs().addClass('ui-tabs-vertical ui-helper-clearfix') + $('#quickReference .ui-tabs-nav li').removeClass('ui-corner-top').addClass('ui-corner-left') }, showDiv: function(selector) { $(selector).show() diff --git a/src/Metamaps/Map/CheatSheet.js b/src/Metamaps/Map/CheatSheet.js deleted file mode 100644 index 0d968b63..00000000 --- a/src/Metamaps/Map/CheatSheet.js +++ /dev/null @@ -1,12 +0,0 @@ -/* global $ */ - -const CheatSheet = { - init: function() { - // tab the cheatsheet - $('#cheatSheet').tabs() - $('#quickReference').tabs().addClass('ui-tabs-vertical ui-helper-clearfix') - $('#quickReference .ui-tabs-nav li').removeClass('ui-corner-top').addClass('ui-corner-left') - } -} - -export default CheatSheet diff --git a/src/Metamaps/Map/index.js b/src/Metamaps/Map/index.js index f337d1d0..b509ed46 100644 --- a/src/Metamaps/Map/index.js +++ b/src/Metamaps/Map/index.js @@ -20,7 +20,6 @@ import ContextMenu from '../Views/ContextMenu' import TopicCard from '../Views/TopicCard' import Visualize from '../Visualize' -import CheatSheet from './CheatSheet' import InfoBox from './InfoBox' const Map = { @@ -45,7 +44,6 @@ const Map = { InfoBox.init(serverData, function updateThumbnail() { self.uploadMapScreenshot() }) - CheatSheet.init(serverData) $(document).on(Map.events.editedByActiveMapper, self.editedByActiveMapper) }, setHasLearnedTopicCreation: function(value) { diff --git a/src/Metamaps/index.js b/src/Metamaps/index.js index 5b0c3b02..a5bae1cf 100644 --- a/src/Metamaps/index.js +++ b/src/Metamaps/index.js @@ -15,7 +15,7 @@ import Import from './Import' import JIT from './JIT' import Listeners from './Listeners' import Loading from './Loading' -import Map, { CheatSheet, InfoBox } from './Map' +import Map, { InfoBox } from './Map' import Mapper from './Mapper' import Mouse from './Mouse' import Organize from './Organize' @@ -52,7 +52,6 @@ Metamaps.JIT = JIT Metamaps.Listeners = Listeners Metamaps.Loading = Loading Metamaps.Map = Map -Metamaps.Map.CheatSheet = CheatSheet Metamaps.Map.InfoBox = InfoBox Metamaps.Maps = {} Metamaps.Mapper = Mapper From c7f29963978457c558793d0a855193d424ae6b6d Mon Sep 17 00:00:00 2001 From: Connor Turland Date: Thu, 8 Mar 2018 10:43:39 -0500 Subject: [PATCH 08/23] bring importdialog into the react app --- README.md | 6 ++- src/Metamaps/GlobalUI/ImportDialog.js | 22 ---------- src/Metamaps/GlobalUI/ReactApp.js | 8 +++- src/Metamaps/Map/index.js | 2 +- src/components/LightBoxes/ImportDialogBox.js | 46 ++++++++++++++++++++ src/components/LightBoxes/index.js | 7 +++ src/routes/App.js | 8 +++- src/routes/MapView/ImportDialogBox.js | 43 ------------------ 8 files changed, 71 insertions(+), 71 deletions(-) create mode 100644 src/components/LightBoxes/ImportDialogBox.js delete mode 100644 src/routes/MapView/ImportDialogBox.js diff --git a/README.md b/README.md index bf5f7e1c..d4609cf2 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,12 @@ Checklist - [x] Request invite code - [x] Request user object itself - [x] Load the metacodes - +- [x] move ImportDialog lightbox into main app - [x] create topic form + - [ ] create synapse form -- [ ] move ImportDialog lightbox into main app +- [ ] replace old loader with react loader +- [ ] ensure exports of maps work - [ ] Notifications: make sure notifications either look nice, or redirect - [ ] Notifications: pagination - [ ] Get actioncable working diff --git a/src/Metamaps/GlobalUI/ImportDialog.js b/src/Metamaps/GlobalUI/ImportDialog.js index c253512d..babe9862 100644 --- a/src/Metamaps/GlobalUI/ImportDialog.js +++ b/src/Metamaps/GlobalUI/ImportDialog.js @@ -1,36 +1,14 @@ /* global $ */ -import React from 'react' -import ReactDOM from 'react-dom' -import outdent from 'outdent' - -import ImportDialogBox from '../../routes/MapView/ImportDialogBox' - -import PasteInput from '../PasteInput' import Map from '../Map' const ImportDialog = { openLightbox: null, closeLightbox: null, - init: function(serverData, openLightbox, closeLightbox) { const self = ImportDialog self.openLightbox = openLightbox self.closeLightbox = closeLightbox - - $('#lightbox_content').append($(outdent` -
    -
    -
    - `)) - ReactDOM.render(React.createElement(ImportDialogBox, { - onFileAdded: PasteInput.handleFile, - exampleImageUrl: serverData['import-example.png'], - downloadScreenshot: ImportDialog.downloadScreenshot, - onExport: format => () => { - window.open(`${window.location.pathname}/export.${format}`, '_blank') - } - }), $('.importDialogWrapper').get(0)) }, show: function() { ImportDialog.openLightbox('import-dialog') diff --git a/src/Metamaps/GlobalUI/ReactApp.js b/src/Metamaps/GlobalUI/ReactApp.js index 08752098..321c0383 100644 --- a/src/Metamaps/GlobalUI/ReactApp.js +++ b/src/Metamaps/GlobalUI/ReactApp.js @@ -16,6 +16,7 @@ import DataFetcher from '../DataFetcher' import { ExploreMaps, ChatView, TopicCard, ContextMenu } from '../Views' import Filter from '../Filter' import JIT from '../JIT' +import PasteInput from '../PasteInput' import Realtime from '../Realtime' import Map, { InfoBox } from '../Map' import Topic from '../Topic' @@ -143,7 +144,12 @@ const ReactApp = { onMapStar: Map.star, onMapUnstar: Map.unstar, initNewTopic: Create.newTopic.init, - initNewSynapse: Create.newSynapse.init + initNewSynapse: Create.newSynapse.init, + importHandleFile: PasteInput.handleFile, + downloadScreenshot: ImportDialog.downloadScreenshot, + onExport: format => () => { + window.open(`${window.location.pathname}/export.${format}`, '_blank') + } } }, getCommonProps: function() { diff --git a/src/Metamaps/Map/index.js b/src/Metamaps/Map/index.js index b509ed46..0bd657f6 100644 --- a/src/Metamaps/Map/index.js +++ b/src/Metamaps/Map/index.js @@ -381,5 +381,5 @@ const Map = { } } -export { CheatSheet, InfoBox } +export { InfoBox } export default Map diff --git a/src/components/LightBoxes/ImportDialogBox.js b/src/components/LightBoxes/ImportDialogBox.js new file mode 100644 index 00000000..e00f998b --- /dev/null +++ b/src/components/LightBoxes/ImportDialogBox.js @@ -0,0 +1,46 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import Dropzone from 'react-dropzone' + +class ImportDialogBox extends Component { + handleFile = (files, e) => { + e.preventDefault() // prevent it from triggering the default drag-drop handler + this.props.onFileAdded(files[0]) + } + + render = () => { + return ( +
    +
    +
    +

    EXPORT

    +
    + Export as CSV +
    +
    + Export as JSON +
    +
    + Download screenshot +
    +

    IMPORT

    +

    To upload a file, drop it here:

    + + Drop files here! + +

    See docs.metamaps.cc for instructions.

    +
    +
    +
    + ) + } +} + +ImportDialogBox.propTypes = { + onFileAdded: PropTypes.func, + downloadScreenshot: PropTypes.func, + onExport: PropTypes.func +} + +export default ImportDialogBox diff --git a/src/components/LightBoxes/index.js b/src/components/LightBoxes/index.js index f851108f..9ed26774 100644 --- a/src/components/LightBoxes/index.js +++ b/src/components/LightBoxes/index.js @@ -3,6 +3,7 @@ import React, { Component } from 'react' import About from './About' import CheatSheet from './CheatSheet' import ForkMap from './ForkMap' +import ImportDialogBox from './ImportDialogBox' import Invite from './Invite' import NoIE from './NoIE' import SwitchMetacodes from './SwitchMetacodes' @@ -10,6 +11,11 @@ import Tutorial from './Tutorial' class LightBoxes extends Component { render = () => { + const importProps = { + onFileAdded: this.props.importHandleFile, + downloadScreenshot: this.props.downloadScreenshot, + onExport: this.props.onExport + } return (