diff --git a/package-lock.json b/package-lock.json index 281e87c..53389b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,8 @@ "react-dom": "^16.14.0", "react-rnd": "^10.4.1", "redux-undo": "^1.0.1", - "sass": "^1.62.1" + "sass": "^1.62.1", + "uuid": "^9.0.1" }, "devDependencies": { "@vitejs/plugin-react": "^4.0.4", @@ -374,342 +375,6 @@ "node": ">=6.9.0" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/@esbuild/win32-x64": { "version": "0.18.20", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", @@ -1906,9 +1571,9 @@ "dev": true }, "node_modules/caniuse-lite": { - "version": "1.0.30001535", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001535.tgz", - "integrity": "sha512-48jLyUkiWFfhm/afF7cQPqPjaUmSraEhK4j+FCTJpgnGGEZHqyLe3hmWH7lIooZdSzXL0ReMvHz0vKDoTBsrwg==", + "version": "1.0.30001609", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001609.tgz", + "integrity": "sha512-JFPQs34lHKx1B5t1EpQpWH4c+29zIyn/haGsbpfq3suuV9v56enjFt23zqijxGTMwy1p/4H2tjnQMY+p1WoAyA==", "dev": true, "funding": [ { @@ -2839,6 +2504,18 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/vite": { "version": "4.4.9", "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", diff --git a/package.json b/package.json index c476216..515560d 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "react-dom": "^16.14.0", "react-rnd": "^10.4.1", "redux-undo": "^1.0.1", - "sass": "^1.62.1" + "sass": "^1.62.1", + "uuid": "^9.0.1" }, "scripts": { "start": "vite", diff --git a/src/App.jsx b/src/App.jsx index 4746b45..ceb1730 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,5 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; -import { useSelector } from 'react-redux'; +import React from 'react'; import './App.scss'; import HeaderMenu from './components/HeaderMenu'; @@ -9,14 +8,15 @@ import TabBar from './components/TabBar'; import Canvas from './components/Canvas'; import Popup from './components/Popup'; -const App = () => { - const activeProject = useSelector(state => state.sessionManager.activeCampaignId || ''); - const [ isToolMenuOpen, setIsToolMenuOpen ] = useState(!!activeProject); - const toolMenuRef = useRef(); +import { useListenerHooks, useMenuStateHooks } from './hooks'; - useEffect(() => { - setIsToolMenuOpen(!!activeProject); - }, [activeProject]); +const App = () => { + useListenerHooks(); + const { + toolMenuRef, + isToolMenuOpen, + toggleToolMenu, + } = useMenuStateHooks(); // Disable scrolling document.body.scroll = 'no'; @@ -24,17 +24,11 @@ const App = () => { document.body.style.overflow = 'hidden'; document.height = window.innerHeight; - // TODO create initialize function and move login stuff into it from Canvas.jsx - return (
{ - if (activeProject) { - setIsToolMenuOpen(!isToolMenuOpen); - } - }} /> + toggleToolMenu={toggleToolMenu} /> diff --git a/src/components-shared/Dropdowns/ActionDropdown.jsx b/src/components-shared/Dropdowns/ActionDropdown.jsx index ddb29b9..6c24b70 100644 --- a/src/components-shared/Dropdowns/ActionDropdown.jsx +++ b/src/components-shared/Dropdowns/ActionDropdown.jsx @@ -8,7 +8,7 @@ import useOutsideClick from '../../utils/useOutsideClick'; { title: 'Move to unsorted', type: ACTION_TYPE.danger, - callback: () => dispatch(actions.unlinkCardFromView(cardId)), + callback: () => dispatch(actions.project.unlinkCardFromView({ id: cardId })), icon: LibraryIcon, }, */ diff --git a/src/components-shared/Dropdowns/ColorDropdown.jsx b/src/components-shared/Dropdowns/ColorDropdown.jsx index e7e99d3..4b087ba 100644 --- a/src/components-shared/Dropdowns/ColorDropdown.jsx +++ b/src/components-shared/Dropdowns/ColorDropdown.jsx @@ -43,7 +43,6 @@ export const ColorDropdown = ({
{ colorList }
- {/* TODO add recent colors */}
); }; diff --git a/src/components/Canvas/hooks.js b/src/components/Canvas/hooks.js index 466a06f..bb0d999 100644 --- a/src/components/Canvas/hooks.js +++ b/src/components/Canvas/hooks.js @@ -1,22 +1,13 @@ import { useEffect, useState } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { ActionCreators } from "redux-undo"; -import * as actions from '../../store/actionIndex'; -import * as fireactions from '../../store/firestoreIndex'; -import { manageUser } from "../../store/firestoreAPI/authTransactions"; +import { actions } from '../../data/redux'; +import * as api from '../../data/api/database'; +import { NETWORK_STATUS } from '../../data/redux/session/constants'; import { GRID } from '../../styles/constants'; import { ANIMATION } from '../Card/hooks'; - -// TODO separate out the network code into functions data/request or something -// link the authlistener and app status management to App.js - -export const NETWORK_STATUS = { - idle: 'idle', - saving: 'saving', - loading: 'loading', -}; +import { DEFAULT_TAB_POSITION, DEFAULT_TAB_SCALE } from '../../data/redux/project/constants'; export const CANVAS_STATES = { empty: 'empty', @@ -25,107 +16,34 @@ export const CANVAS_STATES = { }; export const CANVAS_DIMENSIONS = { - width: 100 * GRID.size, - height: 70 * GRID.size, + width: 150 * GRID.size, + height: 100 * GRID.size, }; export const useCanvasHooks = () => { const dispatch = useDispatch(); - const userId = useSelector((state) => state.userData.userId); - const status = useSelector(state => state.sessionManager.status || NETWORK_STATUS.idle); - const activeProject = useSelector(state => state.sessionManager.activeCampaignId || ''); - const isProjectEdited = useSelector(state => state.sessionManager.campaignEdit); - const isIntroCampaignEdited = useSelector(state => state.sessionManager.introCampaignEdit); - const activeTab = useSelector(state => state.campaignData.present.activeViewId || ''); - const activeTabPosition = useSelector(state => activeTab ? state.campaignData.present.views[activeTab].pos : null); - const activeTabScale = useSelector(state => activeTab ? state.campaignData.present.views[activeTab].scale : 1); - const projectData = useSelector(state => state.campaignData.present); - const cardCollection = useSelector(state => state.campaignData.present.cards); - const latestUnfiltered = useSelector(state => state.campaignData._latestUnfiltered); + const userId = useSelector((state) => state.user.userId); + const status = useSelector(state => state.session.status || NETWORK_STATUS.idle); + const activeProject = useSelector(state => state.session.activeCampaignId || ''); + const activeTab = useSelector(state => state.project.present.activeViewId || ''); + const activeTabPosition = useSelector(state => activeTab ? state.project.present.views[activeTab]?.pos : DEFAULT_TAB_POSITION); + const activeTabScale = useSelector(state => activeTab ? state.project.present.views[activeTab]?.scale : DEFAULT_TAB_SCALE); + const cardCollection = useSelector(state => state.project.present.cards); const [ canvasState, setCanvasState ] = useState(CANVAS_STATES.empty); const [ cardAnimation, setCardAnimation ] = useState({}); - - const isLoggedIn = !!userId; // set canvas state useEffect(() => { if (status === NETWORK_STATUS.loading) { setCanvasState(CANVAS_STATES.loading); - } else if (!!userId && !!activeProject && !!activeTab) { + } else if (!!activeProject && !!activeTab) { setCanvasState(CANVAS_STATES.loaded); } else { setCanvasState(CANVAS_STATES.empty); } }, [status, userId, activeProject, activeTab]); - // auth listener - useEffect(() => { - const authListener = manageUser({ - dispatch, - introCampaignEdit: isIntroCampaignEdited, - campaignData: projectData, - }); - return () => authListener(); - }, [dispatch]); - - // load data for active project - useEffect(() => { - if (isLoggedIn) { - if (activeProject) { - dispatch(fireactions.fetchCampaignData( - activeProject, - () => dispatch(ActionCreators.clearHistory()), - )); - } else { - console.log("[Status] idle. Triggered by activeCampaignId change."); - dispatch(actions.setStatus(NETWORK_STATUS.idle)); - } - } - }, [dispatch, activeProject]); - - // when project data changes, set edited flag - useEffect(() => { - if (isLoggedIn) { - if ((status === NETWORK_STATUS.idle) && !!projectData && (Object.keys(projectData).length !== 0)) { - if (!isProjectEdited) { - dispatch(actions.setCampaignEdit(true)); - } - } else { - console.log("[Status] idle. Triggered by post-load."); - dispatch(actions.setStatus(NETWORK_STATUS.idle)); - } - } else { - if ((status === NETWORK_STATUS.idle) && !!projectData && (Object.keys(projectData).length !== 0)) { - if (!isIntroCampaignEdited) { - dispatch(actions.setIntroCampaignEdit(true)); - } - } else { - console.log("[Status] idle. Triggered by post-load."); - dispatch(actions.setStatus(NETWORK_STATUS.idle)); - } - } - }, [dispatch, latestUnfiltered]) - - // auto-save every minute - useEffect(() => { - const autoSave = setInterval(() => { - if ((status === NETWORK_STATUS.idle) && isLoggedIn && activeProject && isProjectEdited) { - console.log("[Status] saving. Triggered by autosave."); - dispatch(actions.setStatus(NETWORK_STATUS.saving)); - dispatch(fireactions.saveCampaignData( - activeProject, - projectData, - () => { - console.log("[Status] idle. Triggered by autosave completion."); - dispatch(actions.setStatus(NETWORK_STATUS.idle)); - } - )); - } - }, 60000); - return () => clearInterval(autoSave); - }, [dispatch, status, userId, activeProject, isProjectEdited, projectData]); - let cardArgs = {}; for (let card in cardCollection) { if (cardCollection[card].views && cardCollection[card].views[activeTab]) { @@ -146,10 +64,14 @@ export const useCanvasHooks = () => { dragStopHandler: (event, data) => { if (activeTabPosition) { if (activeTabPosition.x !== data.x || activeTabPosition.y !== data.y) { - dispatch(actions.updActiveViewPos({ x: data.x, y: data.y })); + dispatch(actions.project.setActiveTabPosition({ + position: { x: data.x, y: data.y }, + })); } } else { - dispatch(actions.updActiveViewPos({ x: data.x, y: data.y })); + dispatch(actions.project.setActiveTabPosition({ + position: { x: data.x, y: data.y }, + })); } }, wheelHandler: (event) => { @@ -157,7 +79,7 @@ export const useCanvasHooks = () => { newScale += event.deltaY * -0.001; newScale = Math.round(newScale * 10) / 10; newScale = Math.min(Math.max(GRID.scaleMin, newScale), GRID.scaleMax); - dispatch(actions.updActiveViewScale(newScale)); + dispatch(actions.project.setActiveTabScale({ scale: newScale })); }, cardDropHandler: (event) => { event.preventDefault(); @@ -170,7 +92,7 @@ export const useCanvasHooks = () => { x = (x < 0) ? 0 : x; y = (y < 0) ? 0 : y; const position = { x, y }; - dispatch(actions.linkCardToView(droppedCard, position)); + dispatch(actions.project.linkCardToView({ id: droppedCard, position})); } else { setCardAnimation({ ...cardAnimation, @@ -179,6 +101,6 @@ export const useCanvasHooks = () => { } } }, - createNewProject: () => dispatch(fireactions.createProject()), + createNewProject: () => dispatch(api.createAndSwitchToEmptyProject()), }; }; diff --git a/src/components/Card/hooks.js b/src/components/Card/hooks.js index b46191f..89c14bd 100644 --- a/src/components/Card/hooks.js +++ b/src/components/Card/hooks.js @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import useOutsideClick from '../../utils/useOutsideClick'; -import * as actions from '../../store/actionIndex'; +import { actions } from '../../data/redux'; import { CARD_COLOR_KEYS, LIGHT_COLORS } from '../../styles/colors'; import { POPUP_KEYS } from '../Popup/PopupKey'; import { ACTION_TYPE } from '../../components-shared/Dropdowns/ActionDropdown'; @@ -23,11 +23,14 @@ export const useCardHooks = ({ }) => { const dispatch = useDispatch(); - const activeCard = useSelector(state => state.sessionManager.activeCardId); - const activeTab = useSelector(state => state.campaignData.present.activeViewId); - const activeTabScale = useSelector(state => activeTab ? state.campaignData.present.views[activeTab]?.scale : null); - const cardPosition = useSelector(state => state.campaignData.present.cards[cardId].views[activeTab]?.pos); - const cardSize = useSelector(state => state.campaignData.present.cards[cardId].views[activeTab]?.size); + const activeCard = useSelector(state => state.session.activeCardId); + const activeTab = useSelector(state => state.project.present.activeViewId); + const activeTabScale = useSelector(state => activeTab ? state.project.present.views[activeTab]?.scale : null); + const { + pos: cardPosition, + size: cardSize, + } = useSelector( state => state.project.present.cards[cardId].views[activeTab]); + const [isDragging, setIsDragging] = useState(false); const [isSelected, setIsSelected] = useState(false); @@ -39,7 +42,7 @@ export const useCardHooks = ({ useOutsideClick([cardRef, toolMenuRef], isSelected, () => { - if (isActive) dispatch(actions.updActiveCardId(null)); + if (isActive) dispatch(actions.session.setActiveCard({ id: null })); setIsSelected(false); } ); @@ -48,7 +51,7 @@ export const useCardHooks = ({ if (isDragging) { zIndex = 20000 * (cardPosition.y + cardPosition.x + 10); } else if (isActive) { - zIndex = 10000 * (cardPosition.y + cardPosition.x + 10); + zIndex = 20000 * (cardPosition.y + cardPosition.x + 10); } return { @@ -66,23 +69,35 @@ export const useCardHooks = ({ setIsDragging(false); if (cardPosition) { if (cardPosition.x !== data.x || cardPosition.y !== data.y) { - dispatch(actions.updCardPos(cardId, {x: data.x, y: data.y})); + dispatch(actions.project.updateCardPosition({ + id: cardId, + position: { x: data.x, y: data.y }, + })); } } else { - dispatch(actions.updCardPos(cardId, { x: data.x, y: data.y })); + dispatch(actions.project.updateCardPosition({ + id: cardId, + position: { x: data.x, y: data.y }, + })); } }, onResizeStop: (event, direction, ref, delta, position) => { if (delta.width !== 0 || delta.height !== 0) { - dispatch(actions.updCardSize(cardId, {width: ref.style.width, height: ref.style.height})); + dispatch(actions.project.updateCardSize({ + id: cardId, + size: { width: ref.style.width, height: ref.style.height }, + })); if (["top", "left", "topRight", "bottomLeft", "topLeft"].indexOf(direction) !== -1) { - dispatch(actions.updCardPos(cardId, { x: position.x, y: position.y })); + dispatch(actions.project.updateCardPosition({ + id: cardId, + position: { x: position.x, y: position.y }, + })); } } }, onClick: () => { if (!isSelected) { - if (!isActive) dispatch(actions.updActiveCardId(cardId)); + if (!isActive) dispatch(actions.session.setActiveCard({ id: cardId })); setIsSelected(true); } }, @@ -98,9 +113,9 @@ export const useLibraryCardHooks = ({ }) => { const dispatch = useDispatch(); - const activeCard = useSelector(state => state.sessionManager.activeCardId); - const activeTab = useSelector(state => state.campaignData.present.activeViewId); - const cardTabs = useSelector(state => state.campaignData.present.cards[cardId].views); + const activeCard = useSelector(state => state.session.activeCardId); + const activeTab = useSelector(state => state.project.present.activeViewId); + const cardTabs = useSelector(state => state.project.present.cards[cardId].views); const [isSelected, setIsSelected] = useState(false); const [isEditing, setIsEditing] = useState(false); @@ -112,7 +127,7 @@ export const useLibraryCardHooks = ({ useOutsideClick([libraryCardRef], isSelected, () => { - if (isActive) dispatch(actions.updActiveCardId(null)); + if (isActive) dispatch(actions.session.setActiveCard({ id: null })); setIsSelected(false); } ); @@ -139,7 +154,7 @@ export const useLibraryCardHooks = ({ }), onClick: () => { if (!isSelected) { - if (cardId !== activeCard) dispatch(actions.updActiveCardId(cardId)); + if (cardId !== activeCard) dispatch(actions.session.setActiveCard({ id: cardId })); setIsSelected(true); } }, @@ -152,7 +167,7 @@ export const useTitleHooks = ({ }) => { const dispatch = useDispatch(); - const title = useSelector(state => state.campaignData.present.cards[cardId].title); + const title = useSelector(state => state.project.present.cards[cardId].title); const [ titleValue, setTitleValue ] = useState(''); const [ isEditing, setIsEditing ] = useState(false); @@ -169,8 +184,8 @@ export const useTitleHooks = ({ setEditingCard(true); titleRef.current.focus(); titleRef.current.setSelectionRange( - titleRef.current.title.length, - titleRef.current.title.length, + titleRef.current.value.length, + titleRef.current.value.length, ); } }; @@ -178,7 +193,10 @@ export const useTitleHooks = ({ const endTitleEdit = () => { if (isEditing) { document.getSelection().removeAllRanges(); - dispatch(actions.updCardTitle(cardId, titleValue)); + dispatch(actions.project.updateCardTitle({ + id: cardId, + title: titleValue, + })); setIsEditing(false); setEditingCard(false); } @@ -206,7 +224,7 @@ export const useColorDropdownHooks = ({ cardId, }) => { const dispatch = useDispatch(); - let color = useSelector(state => state.campaignData.present.cards[cardId].color); + let color = useSelector(state => state.project.present.cards[cardId].color); color = CARD_COLOR_KEYS[color] ?? CARD_COLOR_KEYS.gray; const [ isColorDropdownOpen, setIsColorDropdownOpen ] = useState(false); const colorDropdownBtnRef = useRef(); @@ -218,7 +236,10 @@ export const useColorDropdownHooks = ({ isLightColor: LIGHT_COLORS.includes(color), openColorDropdown: () => setIsColorDropdownOpen(!isColorDropdownOpen), closeColorDropdown: () => setIsColorDropdownOpen(false), - updateColor: (newColor) => dispatch(actions.updCardColor(cardId, newColor)), + updateColor: (newColor) => dispatch(actions.project.updateCardColor({ + id: cardId, + color: newColor, + })), }; }; @@ -238,7 +259,7 @@ export const useOptionsDropdownHooks = ({ // }, { title: 'Duplicate card', - callback: () => dispatch(actions.copyCard(cardId)), + callback: () => dispatch(actions.project.copyCard({ id: cardId })), }, {}, { @@ -256,7 +277,7 @@ export const useOptionsDropdownHooks = ({ // }, { title: 'Move to unsorted', - callback: () => dispatch(actions.unlinkCardFromView(cardId)), + callback: () => dispatch(actions.project.unlinkCardFromView({ id: cardId })), icon: LibraryIcon, }, {}, @@ -264,7 +285,7 @@ export const useOptionsDropdownHooks = ({ title: 'Delete', type: ACTION_TYPE.danger, icon: RedTrashIcon, - callback: () => dispatch(actions.setPopup({ + callback: () => dispatch(actions.session.setPopup({ type: POPUP_KEYS.confirmCardDelete, id: cardId, })), @@ -285,7 +306,7 @@ export const useContentHooks = ({ setEditingCard, }) => { const dispatch = useDispatch(); - const text = useSelector(state => state.campaignData.present.cards[cardId].content.text); + const text = useSelector(state => state.project.present.cards[cardId].content.text); const [ contentValue, setContentValue ] = useState(''); const [ isEditing, setIsEditing ] = useState(false); @@ -302,8 +323,8 @@ export const useContentHooks = ({ setEditingCard(true); contentRef.current.focus(); contentRef.current.setSelectionRange( - contentRef.current.text.length, - contentRef.current.text.length, + contentRef.current.value.length, + contentRef.current.value.length, ); } }; @@ -311,7 +332,10 @@ export const useContentHooks = ({ const endContentEdit = () => { if (isEditing) { document.getSelection().removeAllRanges(); - dispatch(actions.updCardText(cardId, contentValue)); + dispatch(actions.project.updateCardText({ + id: cardId, + text: contentValue, + })); setIsEditing(false); setEditingCard(false); } diff --git a/src/components/Card/popups/DeleteConfirmation.jsx b/src/components/Card/popups/DeleteConfirmation.jsx index b84725d..22b2c15 100644 --- a/src/components/Card/popups/DeleteConfirmation.jsx +++ b/src/components/Card/popups/DeleteConfirmation.jsx @@ -1,18 +1,19 @@ import React from 'react'; import { useDispatch } from 'react-redux'; +import { actions } from '../../../data/redux'; + import './DeleteConfirmation.scss'; -import * as actions from '../../../store/actionIndex'; export const DeleteConfirmation = ({ id, }) => { const dispatch = useDispatch(); - const cancelClick = () => dispatch(actions.resetPopup()); + const cancelClick = () => dispatch(actions.session.resetPopup()); const confirmClick = () => { - dispatch(actions.destroyCard(id)); - dispatch(actions.resetPopup()); + dispatch(actions.project.destroyCard({ id })); + dispatch(actions.session.resetPopup()); }; return ( diff --git a/src/components/HeaderMenu/Title.jsx b/src/components/HeaderMenu/Title.jsx index 4221ce6..e65e289 100644 --- a/src/components/HeaderMenu/Title.jsx +++ b/src/components/HeaderMenu/Title.jsx @@ -1,38 +1,26 @@ import React from 'react'; -import { useDispatch } from 'react-redux'; -import * as actions from '../../store/actionIndex'; import { useTitleHooks } from './hooks'; import './index.scss'; const Title = () => { - const dispatch = useDispatch(); - const { - inputClassName, - readOnly, titleRef, titleValue, changeTitleValue, - beginTitleEdit, endTitleEdit, handleTitleKeyPress, - } = useTitleHooks({ - saveNewValue: (value) => dispatch(actions.updCampaignTitle(value)), - }); + } = useTitleHooks(); return (
changeTitleValue(e.target.value)} - onDoubleClick={beginTitleEdit} onDragOver={e => e.preventDefault()} onKeyDown={handleTitleKeyPress} - readOnly={readOnly} ref={titleRef} required size='' diff --git a/src/components/HeaderMenu/VersionControls.jsx b/src/components/HeaderMenu/VersionControls.jsx index 4a47d02..bf3151b 100644 --- a/src/components/HeaderMenu/VersionControls.jsx +++ b/src/components/HeaderMenu/VersionControls.jsx @@ -1,6 +1,6 @@ import React from 'react'; -import { useVersionControlHooks } from './hooks'; +import { useVersionControlHooks, SAVE_BUTTON } from './hooks'; import './index.scss'; import UndoDisabledIcon from '../../assets/icons/undo-disabled.svg'; @@ -20,21 +20,21 @@ const VersionControls = () => { redo, disableRedo, save, - saveStatus, + saveButtonStatus, } = useVersionControlHooks(); let saveIcon = SaveEnabledIcon; - switch (saveStatus) { - case 'disabled': + switch (saveButtonStatus) { + case SAVE_BUTTON.disabled: saveIcon = SaveDisabledIcon; break; - case 'pending': + case SAVE_BUTTON.pending: saveIcon = SavePendingIcon; break; - case 'saving': + case SAVE_BUTTON.saving: saveIcon = SaveSpinnerIcon; break; - case 'completed': + case SAVE_BUTTON.completed: saveIcon = SaveCompletedIcon; break; } @@ -57,13 +57,13 @@ const VersionControls = () => {