From a9af56b1d38e9f7a3b9c969dc91bdf314147a119 Mon Sep 17 00:00:00 2001 From: Max Bo Date: Tue, 19 Mar 2019 23:25:08 +1100 Subject: [PATCH] Add drag and drop for the speaker feed (#44) --- package.json | 2 + src/components/caucus/CaucusNextSpeaking.tsx | 2 +- src/components/caucus/SpeakerFeed.tsx | 132 +++++++++++++++---- yarn.lock | 108 ++++++++++++++- 4 files changed, 215 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 4d9bca0e..9df1fa5a 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,14 @@ "@types/lodash": "^4.14.116", "@types/node": "10.12.12", "@types/react": "^16.8.4", + "@types/react-beautiful-dnd": "^10.1.0", "@types/react-dom": "^16.8.2", "@types/react-router-dom": "^4.3.1", "file-saver": "^2.0.0-rc.3", "firebase": "^5.7.0", "lodash": "^4.17.11", "react": "16.8.3", + "react-beautiful-dnd": "^10.0.4", "react-dom": "16.8.3", "react-ga": "^2.5.3", "react-router-dom": "^4.3.1", diff --git a/src/components/caucus/CaucusNextSpeaking.tsx b/src/components/caucus/CaucusNextSpeaking.tsx index 3dad0053..edd70905 100644 --- a/src/components/caucus/CaucusNextSpeaking.tsx +++ b/src/components/caucus/CaucusNextSpeaking.tsx @@ -192,7 +192,7 @@ export class CaucusNextSpeaking extends React.Component { /> diff --git a/src/components/caucus/SpeakerFeed.tsx b/src/components/caucus/SpeakerFeed.tsx index 5ddc10cc..1a6902bd 100644 --- a/src/components/caucus/SpeakerFeed.tsx +++ b/src/components/caucus/SpeakerFeed.tsx @@ -1,9 +1,15 @@ +/** + * This is truly the most fucked up file in the entire codebase. + * Mercy up on all those who must modify this. + */ + import { TimerData } from '../Timer'; import * as React from 'react'; -import { Feed, Icon, Flag, Label } from 'semantic-ui-react'; +import { Feed, Icon, Flag, Label, FeedContent, FeedEvent } from 'semantic-ui-react'; import { runLifecycle, Lifecycle } from '../../actions/caucusActions'; import { parseFlagName } from '../Member'; import { Dictionary } from '../../types'; +import { DragDropContext, Droppable, Draggable, DraggableProvided, DropResult } from 'react-beautiful-dnd'; export enum Stance { For = 'For', @@ -12,7 +18,7 @@ export enum Stance { } export interface SpeakerEvent { - who: string; // FIXME: @mbo you dumb fuck, this was meant to be MemberID, not their fucking name + who: string; stance: Stance; duration: number; } @@ -28,16 +34,17 @@ const StanceIcon = (props: { stance: Stance }) => { } }; -export const SpeakerFeedEntry = (props: { - data?: SpeakerEvent, +export class SpeakerFeedEntry extends React.PureComponent<{ + data?: SpeakerEvent, speaking?: SpeakerEvent, - fref: firebase.database.Reference, - speakerTimer: TimerData -}) => { + fref: firebase.database.Reference, + speakerTimer: TimerData, + draggableProvided?: DraggableProvided +}> { - const { data, speaking, fref, speakerTimer } = props; + yieldHandler = () => { + const { fref, data, speakerTimer, speaking } = this.props; - const yieldHandler = () => { const queueHeadDetails = { queueHeadData: data, queueHead: fref @@ -63,8 +70,10 @@ export const SpeakerFeedEntry = (props: { runLifecycle({ ...lifecycle, ...queueHeadDetails }); }; - return data ? ( - + renderContent() { + const { data, speaking, fref } = this.props; + + return data ? ( @@ -81,40 +90,109 @@ export const SpeakerFeedEntry = (props: { - {speaking && ( - - ) : ; + ) : + } + + render() { + const { draggableProvided } = this.props; + + return draggableProvided ? ( +
+ {this.renderContent()} +
+ ) : + {this.renderContent()} + + } +}; + +function reorder(list: T[], startIndex: number, endIndex: number) { + const result = Array.from(list); + const [removed] = result.splice(startIndex, 1); + result.splice(endIndex, 0, removed); + + return result; }; export const SpeakerFeed = (props: { data?: Dictionary, - fref: firebase.database.Reference, + queueFref: firebase.database.Reference, speaking?: SpeakerEvent, speakerTimer: TimerData }) => { - const { data, fref, speaking, speakerTimer } = props; + const { data, queueFref, speaking, speakerTimer } = props; const events = data || {}; - const eventItems = Object.keys(events).map(key => + const eventItems = Object.keys(events).map((key, index) => ( - + + {(provided, snapshot) => + + } + ) ); + const onDragEnd = (result: DropResult) => { + // dropped outside the list + if (!result.destination) { + return; + } + + const events = data || {}; + + const reorderedKeys = reorder( + Object.keys(events), + result.source.index, + result.destination.index + ); + + queueFref.set({}); + + reorderedKeys.forEach(key => { + const se = (data || {})[key] + + if (se) { + queueFref.push().set(se); + } + }); + } + return ( - - {eventItems} - + + + {(provided, snapshot) => +
+ + {eventItems} + +
+ } +
+
); }; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index e2a48652..fefd4323 100644 --- a/yarn.lock +++ b/yarn.lock @@ -782,6 +782,14 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-typescript" "^7.1.0" +"@babel/runtime-corejs2@^7.3.0": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.3.4.tgz#63f8bbc77622da202e9ea6f8f6e3bf28991832d9" + integrity sha512-QwPuQE65kNxjsNKk34Rfgen2R5fk0J2So99SD45uXBp34QOfyz11SqVgJ4xvyCpnCIieSQ0X0hSSc9z/ymlJJw== + dependencies: + core-js "^2.5.7" + regenerator-runtime "^0.12.0" + "@babel/runtime@7.3.1": version "7.3.1" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.1.tgz#574b03e8e8a9898eaf4a872a92ea20b7846f6f2a" @@ -796,6 +804,13 @@ dependencies: regenerator-runtime "^0.12.0" +"@babel/runtime@^7.1.2": + version "7.3.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.4.tgz#73d12ba819e365fcf7fd152aed56d6df97d21c83" + integrity sha512-IvfvnMdSaLBateu0jfsYIpZTxAc2cKEXEMiezGGN75QcBcecDUKd3PgLAncT0oOgxKy8dd8hrJKj9MfzgfZd6g== + dependencies: + regenerator-runtime "^0.12.0" + "@babel/template@^7.1.0", "@babel/template@^7.1.2": version "7.1.2" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.1.2.tgz#090484a574fef5a2d2d7726a674eceda5c5b5644" @@ -1282,6 +1297,13 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.1.tgz#48fd98c1561fe718b61733daed46ff115b496e18" integrity sha512-eqz8c/0kwNi/OEHQfvIuJVLTst3in0e7uTKeuY+WL/zfKn0xVujOTp42bS/vUUokhK5P2BppLd9JXMOMHcgbjA== +"@types/react-beautiful-dnd@^10.1.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-10.1.0.tgz#6aa032519051a793154abaca2989d0f070a01680" + integrity sha512-f2qsG2vlydADYF535EmtWj5J71baIOplXcSdticKuQ3Ierf+jtbcOA1Ptb9H3lAcQgscJC64NlkVt6wTQlV7WQ== + dependencies: + "@types/react" "*" + "@types/react-dom@^16.8.2": version "16.8.2" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.2.tgz#9bd7d33f908b243ff0692846ef36c81d4941ad12" @@ -3095,6 +3117,11 @@ core-js@^2.4.0, core-js@^2.5.0: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e" integrity sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw== +core-js@^2.5.7: + version "2.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895" + integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A== + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -3211,6 +3238,13 @@ css-blank-pseudo@^0.1.4: dependencies: postcss "^7.0.5" +css-box-model@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.1.1.tgz#c9fd8e7a8b1d59d41d6812fd1765433f671b2ee0" + integrity sha512-ZxbuLFeAPEDb0wPbGfT7783Vb00MVAkvOlMKwr0kA2PD5EGxk6P3MAhedvVuyVJCWb54bb+6HQ7pdPYENf8AZw== + dependencies: + tiny-invariant "^1.0.3" + css-color-names@0.0.4, css-color-names@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -5222,6 +5256,13 @@ hoist-non-react-statics@^2.5.0: resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== +hoist-non-react-statics@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" + integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== + dependencies: + react-is "^16.7.0" + home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -6889,7 +6930,7 @@ long@~3: resolved "https://registry.yarnpkg.com/long/-/long-3.2.0.tgz#d821b7138ca1cb581c172990ef14db200b5c474b" integrity sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s= -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -6999,6 +7040,11 @@ mem@^4.0.0: mimic-fn "^1.0.0" p-is-promise "^1.1.0" +memoize-one@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.0.tgz#d55007dffefb8de7546659a1722a5d42e128286e" + integrity sha512-7g0+ejkOaI9w5x6LvQwmj68kUj6rxROywPSCqmclG/HBacmFnZqhVscQ8kovkn9FBCNJmOz6SY42+jnvZzDWdw== + memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -8917,6 +8963,11 @@ querystringify@^2.0.0: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.0.0.tgz#fa3ed6e68eb15159457c89b37bc6472833195755" integrity sha512-eTPo5t/4bgaMNZxyjWx6N2a6AuE0mq51KWvpc7nU/MAqixcI6v6KrGUKES0HaomdnolQBBXU/++X6/QQ9KL4tw== +raf-schd@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.0.tgz#9855756c5045ff4ed4516e14a47719387c3c907b" + integrity sha512-m7zq0JkIrECzw9mO5Zcq6jN4KayE34yoIS9hJoiZNXyOAT06PPA8PrR+WtJIeFW09YjUfNkMMN9lrmAt6BURCA== + raf@3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" @@ -8989,6 +9040,20 @@ react-app-polyfill@^0.2.1: raf "3.4.1" whatwg-fetch "3.0.0" +react-beautiful-dnd@^10.0.4: + version "10.0.4" + resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-10.0.4.tgz#56913a77706ad2d1b002041d9cb1ac3849a4ae89" + integrity sha512-j2Ra/mW48tXz1Mk6bNBuiENpRBt8wQcPbJgHSswmLDonUE8JPwVikaONoMavdowoMKQJoOJ9IwPTo82d/8aKKg== + dependencies: + "@babel/runtime-corejs2" "^7.3.0" + css-box-model "^1.1.1" + memoize-one "^5.0.0" + prop-types "^15.6.1" + raf-schd "^4.0.0" + react-redux "^5.0.7" + redux "^4.0.1" + tiny-invariant "^1.0.3" + react-dev-utils@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-7.0.3.tgz#f1316cfffd792fd41b0c28ad5db86c1d74484d6f" @@ -9042,6 +9107,29 @@ react-ga@^2.5.3: prop-types "^15.6.0" react "^15.6.2 || ^16.0" +react-is@^16.6.0, react-is@^16.7.0: + version "16.8.4" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.4.tgz#90f336a68c3a29a096a3d648ab80e87ec61482a2" + integrity sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA== + +react-lifecycles-compat@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-redux@^5.0.7: + version "5.1.1" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.1.tgz#88e368682c7fa80e34e055cd7ac56f5936b0f52f" + integrity sha512-LE7Ned+cv5qe7tMV5BPYkGQ5Lpg8gzgItK07c67yHvJ8t0iaD9kPFPAli/mYkiyJYrs2pJgExR2ZgsGqlrOApg== + dependencies: + "@babel/runtime" "^7.1.2" + hoist-non-react-statics "^3.1.0" + invariant "^2.2.4" + loose-envify "^1.1.0" + prop-types "^15.6.1" + react-is "^16.6.0" + react-lifecycles-compat "^3.0.0" + react-router-dom@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.3.1.tgz#4c2619fc24c4fa87c9fd18f4fb4a43fe63fbd5c6" @@ -9231,6 +9319,14 @@ recursive-readdir@2.2.2: dependencies: minimatch "3.0.4" +redux@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.1.tgz#436cae6cc40fbe4727689d7c8fae44808f1bfef5" + integrity sha512-R7bAtSkk7nY6O/OYMVR9RiBI+XghjF9rlbl5806HJbQph0LJVHZrU5oaO4q70eUKiqMRqm4y07KLTlMZ2BlVmg== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + regenerate-unicode-properties@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz#107405afcc4a190ec5ed450ecaa00ed0cafa7a4c" @@ -10361,6 +10457,11 @@ symbol-observable@1.0.1: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= +symbol-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + symbol-tree@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" @@ -10473,6 +10574,11 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tiny-invariant@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.3.tgz#91efaaa0269ccb6271f0296aeedb05fc3e067b7a" + integrity sha512-ytQx8T4DL8PjlX53yYzcIC0WhIZbpR0p1qcYjw2pHu3w6UtgWwFJQ/02cnhOnBBhlFx/edUIfcagCaQSe3KMWg== + tmp@0.0.31: version "0.0.31" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"