From c9ed1401b769cb3774f4595f248f7f5a2b1623ef Mon Sep 17 00:00:00 2001 From: Alec Rollison <88508028+aelishRollo@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:37:16 -0400 Subject: [PATCH 01/11] Get basic template working so I can begin developing --- src/App.test.tsx | 201 ----------------------------------------------- src/App.tsx | 63 +-------------- src/Foo.tsx | 8 ++ src/index.tsx | 12 +-- 4 files changed, 13 insertions(+), 271 deletions(-) delete mode 100644 src/App.test.tsx create mode 100644 src/Foo.tsx diff --git a/src/App.test.tsx b/src/App.test.tsx deleted file mode 100644 index 8e27742..0000000 --- a/src/App.test.tsx +++ /dev/null @@ -1,201 +0,0 @@ -import {render, screen, waitFor} from '@testing-library/react'; -import App from './App'; -import {IClient} from './client/IClient'; -import {ProjectData, CommentData, SectionData, EntityType, FileData} from './types'; -import {LocalStorageStore, StoreData} from './store/LocalStorageStore'; -import {MockLocalStorageDependency} from './store/MockLocalStorageDependency'; -import {LocalStorageClient} from './client/LocalStorageClient'; - -// import * as testData from './sampleData' - -window.alert = () => {}; - -const makeTestStore = (): StoreData => { - const initialProjects: ProjectData[] = [ - { - id: 'project-1', - }, - { - id: 'project-2', - }, - ]; - - const initialSections: SectionData[] = [ - { - id: 'section-1', - projectId: 'project-1', - chordProgression: ['C', 'Dm', 'F', 'G'], - description: 'This is the intro', - title: 'Intro', - numRevisions: 3, - } - ]; - - const initialFiles: FileData[] = [ - { - id: 'file-1', - projectId: 'project-1', - entityId: 'section-1', - entityType: EntityType.SECTION, - title: 'Bass.mp3', - }, - { - id: 'file-2', - projectId: 'project-1', - entityId: 'section-1', - entityType: EntityType.SECTION, - title: 'Chunky Monkey.mp3', - }, - ]; - - const initialComments: CommentData[] = [ - { - id: 'comment-1', - projectId: 'project-1', - message: 'Hey what\'s up', - entityType: EntityType.SECTION, - entityId: 'section-1', - username: 'username-1', - }, - { - id: 'comment-2', - projectId: 'project-1', - message: 'Yeah', - entityType: EntityType.FILE, - entityId: 'file-1', - username: 'username-1', - }, - { - id: 'comment-3', - projectId: 'project-1', - message: 'Yeah 3', - entityType: EntityType.FILE, - entityId: 'file-1', - username: 'username-1', - }, - ]; - - return { - projects: initialProjects, - sections: initialSections, - files: initialFiles, - comments: initialComments, - }; -}; - -describe('App', () => { - let client: IClient; - - beforeEach(() => { - const initialStore = makeTestStore(); - - const localStorageDependency = new MockLocalStorageDependency(initialStore); - const store = new LocalStorageStore(localStorageDependency); - client = new LocalStorageClient(store); - }); - - describe('initializing', () => { - it('should show "Loading"', async () => { - // this method is made blocking for this specific test - client.fetchFullDataForProject = (() => new Promise(r => setTimeout(r))); - - render( - - ); - - expect(screen.getByText(/Loading/)).toBeDefined(); - }); - - it('should show client error', async () => { - client.fetchFullDataForProject = jest.fn().mockResolvedValue(new Error('Some error')); - - render( - - ); - - await waitFor(() => { - expect(screen.queryByText(/Loading/)).toBeNull(); - }); - - expect(screen.getByText(/Some error/)).toBeDefined(); - }); - }); - - describe('initialized', () => { - it('should show the section title and description', async () => { - render( - - ); - - await waitFor(() => { - expect(screen.queryByText(/Loading/)).toBeNull(); - }); - - expect(screen.getByText(/Intro/)).toBeDefined(); - expect(screen.getByText(/This is the intro/)).toBeDefined(); - }); - - it('should show the chord progression', async () => { - const {container} = render( - - ); - - await waitFor(() => { - expect(screen.queryByText(/Loading/)).toBeNull(); - }); - - expect(container.querySelector('.chords')?.textContent).toEqual('CDmFG'); - }); - - it('should show files attached to the section', async () => { - const {container} = render( - - ); - - await waitFor(() => { - expect(screen.queryByText(/Loading/)).toBeNull(); - }); - - expect(container.querySelector('.files #file-1')?.textContent).toContain('Bass.mp3'); - expect(container.querySelector('.files #file-1')?.textContent).toContain('2 Comments'); - }); - - it('should show the comments on the section', async () => { - const {container} = render( - - ); - - await waitFor(() => { - expect(screen.queryByText(/Loading/)).toBeNull(); - }); - - expect(container.querySelector('.comments')?.textContent).toContain('1 Comment'); - expect(container.querySelector('.comments #comment-1')?.textContent).toContain('username-1'); - expect(container.querySelector('.comments #comment-1')?.textContent).toContain('Hey what\'s up'); - }); - }); -}); diff --git a/src/App.tsx b/src/App.tsx index df11b80..7d3e3b5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,68 +1,13 @@ -import {useState} from 'react'; -import './App.css'; -import './css_reset.css' -import './index.css' -import './section_view.css'; -import * as types from './types'; -import {GlobalStoreProvider} from './hooks/useGlobalStore'; -import SectionPage from './SectionPage'; -import {IClient} from './client/IClient'; -import {ClientProvider} from './hooks/useClient'; -import {useMount} from './hooks/useMount'; -type AppProps = { - projectId: string; - sectionId: string; +import Foo from './Foo' - client: IClient; -} - -const App: React.FC = ({projectId, sectionId, client}) => { - const [initialProjectData, setInitialProjectData] = useState(null); - const [error, setError] = useState(''); - - useMount(async () => { - const projectDataOrError = await client.fetchFullDataForProject(projectId); - - if (projectDataOrError instanceof Error) { - alert(projectDataOrError.message); - setError(projectDataOrError.message); - return; - } - setInitialProjectData(projectDataOrError); - }); - - if (error) { - return ( - - {error} - - ); - } - - if (!initialProjectData) { - return ( - - Loading - - ); - } - - const pageContent = ( - - ); +const App = () => { + return ( - - - {pageContent} - - + ); } diff --git a/src/Foo.tsx b/src/Foo.tsx new file mode 100644 index 0000000..fae4aa2 --- /dev/null +++ b/src/Foo.tsx @@ -0,0 +1,8 @@ + + + +let ChordProgression = () => { + return ( Hello, Universe!); + }; + + export default ChordProgression diff --git a/src/index.tsx b/src/index.tsx index 7b20240..15f2911 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -11,19 +11,9 @@ window.addEventListener('load', async () => { document.getElementById('root') as HTMLElement ); - const localStore = new LocalStorageStore(localStorage); - const localClient = new LocalStorageClient(localStore); - - const projectId = 'project-1'; - const sectionId = 'section-1'; - root.render( - + ); }); From 5351b3f6d330dd2591b174d7bd0423e2e16c2c86 Mon Sep 17 00:00:00 2001 From: Alec Rollison <88508028+aelishRollo@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:45:34 -0400 Subject: [PATCH 02/11] Prepare to integrate Semantic UI library --- src/index.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 15f2911..eef7cf9 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,8 +3,6 @@ import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; -import {LocalStorageStore} from './store/LocalStorageStore'; -import {LocalStorageClient} from './client/LocalStorageClient'; window.addEventListener('load', async () => { const root = ReactDOM.createRoot( From 228103346ffc676290608b8d17495e55187b1099 Mon Sep 17 00:00:00 2001 From: Alec Rollison <88508028+aelishRollo@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:30:47 -0400 Subject: [PATCH 03/11] Create static layout --- package-lock.json | 146 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 + src/Foo.tsx | 101 ++++++++++++++++++++++++++++++-- src/index.tsx | 2 + 4 files changed, 247 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index a3253ef..2a79a83 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,8 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", + "semantic-ui-css": "^2.5.0", + "semantic-ui-react": "^2.1.5", "typescript": "^4.9.5", "web-vitals": "^2.1.4" } @@ -2402,6 +2404,36 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fluentui/react-component-event-listener": { + "version": "0.63.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-component-event-listener/-/react-component-event-listener-0.63.1.tgz", + "integrity": "sha512-gSMdOh6tI3IJKZFqxfQwbTpskpME0CvxdxGM2tdglmf6ZPVDi0L4+KKIm+2dN8nzb8Ya1A8ZT+Ddq0KmZtwVQg==", + "dependencies": { + "@babel/runtime": "^7.10.4" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/@fluentui/react-component-ref": { + "version": "0.63.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-component-ref/-/react-component-ref-0.63.1.tgz", + "integrity": "sha512-8MkXX4+R3i80msdbD4rFpEB4WWq2UDvGwG386g3ckIWbekdvN9z2kWAd9OXhRGqB7QeOsoAGWocp6gAMCivRlw==", + "dependencies": { + "@babel/runtime": "^7.10.4", + "react-is": "^16.6.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, + "node_modules/@fluentui/react-component-ref/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/@fortawesome/fontawesome-common-types": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.2.tgz", @@ -3428,6 +3460,15 @@ } } }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@rollup/plugin-babel": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz", @@ -3507,6 +3548,19 @@ "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.1.tgz", "integrity": "sha512-S3Kq8e7LqxkA9s7HKLqXGTGck1uwis5vAXan3FnU5yw1Ec5hsSGnq4s/UCaSqABPOnOTg7zASLyst7+ohgWexg==" }, + "node_modules/@semantic-ui-react/event-stack": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@semantic-ui-react/event-stack/-/event-stack-3.1.3.tgz", + "integrity": "sha512-FdTmJyWvJaYinHrKRsMLDrz4tTMGdFfds299Qory53hBugiDvGC0tEJf+cHsi5igDwWb/CLOgOiChInHwq8URQ==", + "dependencies": { + "exenv": "^1.2.2", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/@sinclair/typebox": { "version": "0.24.51", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", @@ -5988,6 +6042,14 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -8107,6 +8169,11 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==" + }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -12002,6 +12069,11 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -12166,6 +12238,11 @@ "node": ">=4.0" } }, + "node_modules/keyboard-key": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keyboard-key/-/keyboard-key-1.1.0.tgz", + "integrity": "sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ==" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -12296,6 +12373,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -14935,11 +15017,30 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, + "node_modules/react-popper": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.3.0.tgz", + "integrity": "sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==", + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17 || ^18", + "react-dom": "^16.8.0 || ^17 || ^18" + } + }, "node_modules/react-refresh": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", @@ -15605,6 +15706,38 @@ "node": ">=10" } }, + "node_modules/semantic-ui-css": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/semantic-ui-css/-/semantic-ui-css-2.5.0.tgz", + "integrity": "sha512-jIWn3WXXE2uSaWCcB+gVJVRG3masIKtTMNEP2X8Aw909H2rHpXGneYOxzO3hT8TpyvB5/dEEo9mBFCitGwoj1A==", + "dependencies": { + "jquery": "x.*" + } + }, + "node_modules/semantic-ui-react": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/semantic-ui-react/-/semantic-ui-react-2.1.5.tgz", + "integrity": "sha512-nIqmmUNpFHfovEb+RI2w3E2/maZQutd8UIWyRjf1SLse+XF51hI559xbz/sLN3O6RpLjr/echLOOXwKCirPy3Q==", + "dependencies": { + "@babel/runtime": "^7.10.5", + "@fluentui/react-component-event-listener": "~0.63.0", + "@fluentui/react-component-ref": "~0.63.0", + "@popperjs/core": "^2.6.0", + "@semantic-ui-react/event-stack": "^3.1.3", + "clsx": "^1.1.1", + "keyboard-key": "^1.1.0", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "prop-types": "^15.7.2", + "react-is": "^16.8.6 || ^17.0.0 || ^18.0.0", + "react-popper": "^2.3.0", + "shallowequal": "^1.1.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/semver": { "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", @@ -15803,6 +15936,11 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -17267,6 +17405,14 @@ "makeerror": "1.0.12" } }, + "node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", diff --git a/package.json b/package.json index c2058f8..f69bf67 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-scripts": "5.0.1", + "semantic-ui-css": "^2.5.0", + "semantic-ui-react": "^2.1.5", "typescript": "^4.9.5", "web-vitals": "^2.1.4" }, diff --git a/src/Foo.tsx b/src/Foo.tsx index fae4aa2..cef8c51 100644 --- a/src/Foo.tsx +++ b/src/Foo.tsx @@ -1,8 +1,101 @@ +import React from 'react'; +import { Container, Header, Menu, Dropdown, Grid, Comment, Form, Button, Input, List } from 'semantic-ui-react'; +const SectionView = () => ( + + {/* Menu */} + + + My section + + + + + Edit title + Edit Progression + Duplicate + Delete + + + + + {/* Chord Progression */} + Progression: C Dm Em F -let ChordProgression = () => { - return ( Hello, Universe!); - }; + {/* Grid Layout */} + + + + + + + + Bass.mp3 + 2 comments + + + + + + Guitar.mp3 + 23 comments + + + + + + Guitar.mp3 + 23 comments + + + + + + + + + Guitar.mp3 + 23 comments + + + + + + Guitar.mp3 + 23 comments + + + + + - export default ChordProgression + {/* Comments Section */} + Comments for section + + + + + Dave + Great section! + + + + + + Matthews + Great section! + + + {/* Add more comments as needed */} + + + {/* Comment Form */} + + + + + +); + +export default SectionView; diff --git a/src/index.tsx b/src/index.tsx index eef7cf9..6537f88 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,6 +3,8 @@ import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; +import 'semantic-ui-css/semantic.min.css'; + window.addEventListener('load', async () => { const root = ReactDOM.createRoot( From 559a12f75fe287bbf844ca589e6a1df9b2b71fe7 Mon Sep 17 00:00:00 2001 From: mickmister <6913320+mickmister@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:51:54 -0400 Subject: [PATCH 04/11] fix ci linting --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f69bf67..04f01cf 100644 --- a/package.json +++ b/package.json @@ -25,11 +25,11 @@ }, "scripts": { "start": "react-scripts start", - "build": "react-scripts build", + "build": "DISABLE_ESLINT_PLUGIN=true react-scripts build", "test": "react-scripts test", "test:ci": "react-scripts test --watchAll=false", "eject": "react-scripts eject", - "lint": "eslint src/**/*.ts*", + "lint": "DISABLE_ESLINT_PLUGIN=false react-scripts build", "fix": "npm run lint -- --fix", "check-types": "tsc --noEmit", "ci": "npm run lint && npm run check-types && npm run test:ci && npm run build" From b351255a897ce5e7612426e46116e8ebf19a9b89 Mon Sep 17 00:00:00 2001 From: Michael Kochell <6913320+mickmister@users.noreply.github.com> Date: Sun, 9 Jun 2024 22:25:06 -0400 Subject: [PATCH 05/11] lint --- src/Foo.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Foo.tsx b/src/Foo.tsx index cef8c51..b76387a 100644 --- a/src/Foo.tsx +++ b/src/Foo.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { Container, Header, Menu, Dropdown, Grid, Comment, Form, Button, Input, List } from 'semantic-ui-react'; +import { Container, Header, Menu, Dropdown, Grid, Comment, Form, Button, List } from 'semantic-ui-react'; const SectionView = () => ( From ca710feac38b3cc371cadeacf7ba657d61290393 Mon Sep 17 00:00:00 2001 From: Michael Kochell <6913320+mickmister@users.noreply.github.com> Date: Sat, 29 Jun 2024 14:48:07 -0400 Subject: [PATCH 06/11] undo file deletions --- src/App.test.tsx | 201 +++++++++++++++++++++++++++++++++++++++++++++++ src/App.tsx | 63 ++++++++++++++- src/index.tsx | 16 +++- 3 files changed, 273 insertions(+), 7 deletions(-) create mode 100644 src/App.test.tsx diff --git a/src/App.test.tsx b/src/App.test.tsx new file mode 100644 index 0000000..8e27742 --- /dev/null +++ b/src/App.test.tsx @@ -0,0 +1,201 @@ +import {render, screen, waitFor} from '@testing-library/react'; +import App from './App'; +import {IClient} from './client/IClient'; +import {ProjectData, CommentData, SectionData, EntityType, FileData} from './types'; +import {LocalStorageStore, StoreData} from './store/LocalStorageStore'; +import {MockLocalStorageDependency} from './store/MockLocalStorageDependency'; +import {LocalStorageClient} from './client/LocalStorageClient'; + +// import * as testData from './sampleData' + +window.alert = () => {}; + +const makeTestStore = (): StoreData => { + const initialProjects: ProjectData[] = [ + { + id: 'project-1', + }, + { + id: 'project-2', + }, + ]; + + const initialSections: SectionData[] = [ + { + id: 'section-1', + projectId: 'project-1', + chordProgression: ['C', 'Dm', 'F', 'G'], + description: 'This is the intro', + title: 'Intro', + numRevisions: 3, + } + ]; + + const initialFiles: FileData[] = [ + { + id: 'file-1', + projectId: 'project-1', + entityId: 'section-1', + entityType: EntityType.SECTION, + title: 'Bass.mp3', + }, + { + id: 'file-2', + projectId: 'project-1', + entityId: 'section-1', + entityType: EntityType.SECTION, + title: 'Chunky Monkey.mp3', + }, + ]; + + const initialComments: CommentData[] = [ + { + id: 'comment-1', + projectId: 'project-1', + message: 'Hey what\'s up', + entityType: EntityType.SECTION, + entityId: 'section-1', + username: 'username-1', + }, + { + id: 'comment-2', + projectId: 'project-1', + message: 'Yeah', + entityType: EntityType.FILE, + entityId: 'file-1', + username: 'username-1', + }, + { + id: 'comment-3', + projectId: 'project-1', + message: 'Yeah 3', + entityType: EntityType.FILE, + entityId: 'file-1', + username: 'username-1', + }, + ]; + + return { + projects: initialProjects, + sections: initialSections, + files: initialFiles, + comments: initialComments, + }; +}; + +describe('App', () => { + let client: IClient; + + beforeEach(() => { + const initialStore = makeTestStore(); + + const localStorageDependency = new MockLocalStorageDependency(initialStore); + const store = new LocalStorageStore(localStorageDependency); + client = new LocalStorageClient(store); + }); + + describe('initializing', () => { + it('should show "Loading"', async () => { + // this method is made blocking for this specific test + client.fetchFullDataForProject = (() => new Promise(r => setTimeout(r))); + + render( + + ); + + expect(screen.getByText(/Loading/)).toBeDefined(); + }); + + it('should show client error', async () => { + client.fetchFullDataForProject = jest.fn().mockResolvedValue(new Error('Some error')); + + render( + + ); + + await waitFor(() => { + expect(screen.queryByText(/Loading/)).toBeNull(); + }); + + expect(screen.getByText(/Some error/)).toBeDefined(); + }); + }); + + describe('initialized', () => { + it('should show the section title and description', async () => { + render( + + ); + + await waitFor(() => { + expect(screen.queryByText(/Loading/)).toBeNull(); + }); + + expect(screen.getByText(/Intro/)).toBeDefined(); + expect(screen.getByText(/This is the intro/)).toBeDefined(); + }); + + it('should show the chord progression', async () => { + const {container} = render( + + ); + + await waitFor(() => { + expect(screen.queryByText(/Loading/)).toBeNull(); + }); + + expect(container.querySelector('.chords')?.textContent).toEqual('CDmFG'); + }); + + it('should show files attached to the section', async () => { + const {container} = render( + + ); + + await waitFor(() => { + expect(screen.queryByText(/Loading/)).toBeNull(); + }); + + expect(container.querySelector('.files #file-1')?.textContent).toContain('Bass.mp3'); + expect(container.querySelector('.files #file-1')?.textContent).toContain('2 Comments'); + }); + + it('should show the comments on the section', async () => { + const {container} = render( + + ); + + await waitFor(() => { + expect(screen.queryByText(/Loading/)).toBeNull(); + }); + + expect(container.querySelector('.comments')?.textContent).toContain('1 Comment'); + expect(container.querySelector('.comments #comment-1')?.textContent).toContain('username-1'); + expect(container.querySelector('.comments #comment-1')?.textContent).toContain('Hey what\'s up'); + }); + }); +}); diff --git a/src/App.tsx b/src/App.tsx index 7d3e3b5..df11b80 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,13 +1,68 @@ +import {useState} from 'react'; +import './App.css'; +import './css_reset.css' +import './index.css' +import './section_view.css'; +import * as types from './types'; +import {GlobalStoreProvider} from './hooks/useGlobalStore'; +import SectionPage from './SectionPage'; +import {IClient} from './client/IClient'; +import {ClientProvider} from './hooks/useClient'; +import {useMount} from './hooks/useMount'; -import Foo from './Foo' +type AppProps = { + projectId: string; + sectionId: string; + client: IClient; +} + +const App: React.FC = ({projectId, sectionId, client}) => { + const [initialProjectData, setInitialProjectData] = useState(null); + const [error, setError] = useState(''); + + useMount(async () => { + const projectDataOrError = await client.fetchFullDataForProject(projectId); + + if (projectDataOrError instanceof Error) { + alert(projectDataOrError.message); + setError(projectDataOrError.message); + return; + } -const App = () => { - + setInitialProjectData(projectDataOrError); + }); + + if (error) { + return ( + + {error} + + ); + } + + if (!initialProjectData) { + return ( + + Loading + + ); + } + + const pageContent = ( + + ); return ( - + + + {pageContent} + + ); } diff --git a/src/index.tsx b/src/index.tsx index 6537f88..7b20240 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,17 +3,27 @@ import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; -import 'semantic-ui-css/semantic.min.css'; - +import {LocalStorageStore} from './store/LocalStorageStore'; +import {LocalStorageClient} from './client/LocalStorageClient'; window.addEventListener('load', async () => { const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); + const localStore = new LocalStorageStore(localStorage); + const localClient = new LocalStorageClient(localStore); + + const projectId = 'project-1'; + const sectionId = 'section-1'; + root.render( - + ); }); From c21b95984eb996aa4e8c17a5e768f1c47b4cebfa Mon Sep 17 00:00:00 2001 From: Michael Kochell <6913320+mickmister@users.noreply.github.com> Date: Sat, 29 Jun 2024 15:01:11 -0400 Subject: [PATCH 07/11] remove unused css files --- src/App.css | 38 ---------- src/App.tsx | 11 +-- src/css_reset.css | 48 ------------- src/index.css | 13 ---- src/index.tsx | 2 +- src/section_view.css | 168 ------------------------------------------- 6 files changed, 3 insertions(+), 277 deletions(-) delete mode 100644 src/App.css delete mode 100644 src/css_reset.css delete mode 100644 src/index.css delete mode 100644 src/section_view.css diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 74b5e05..0000000 --- a/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/App.tsx b/src/App.tsx index df11b80..73aeb62 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,15 +1,11 @@ import {useState} from 'react'; -import './App.css'; -import './css_reset.css' -import './index.css' -import './section_view.css'; import * as types from './types'; import {GlobalStoreProvider} from './hooks/useGlobalStore'; -import SectionPage from './SectionPage'; import {IClient} from './client/IClient'; import {ClientProvider} from './hooks/useClient'; import {useMount} from './hooks/useMount'; +import SectionView from './Foo'; type AppProps = { projectId: string; @@ -51,10 +47,7 @@ const App: React.FC = ({projectId, sectionId, client}) => { } const pageContent = ( - + ); return ( diff --git a/src/css_reset.css b/src/css_reset.css deleted file mode 100644 index e29c0f5..0000000 --- a/src/css_reset.css +++ /dev/null @@ -1,48 +0,0 @@ -/* http://meyerweb.com/eric/tools/css/reset/ - v2.0 | 20110126 - License: none (public domain) -*/ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -/* HTML5 display-role reset for older browsers */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} -body { - line-height: 1; -} -ol, ul { - list-style: none; -} -blockquote, q { - quotes: none; -} -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} diff --git a/src/index.css b/src/index.css deleted file mode 100644 index ec2585e..0000000 --- a/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/src/index.tsx b/src/index.tsx index 7b20240..800a217 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,10 +1,10 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; -import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import {LocalStorageStore} from './store/LocalStorageStore'; import {LocalStorageClient} from './client/LocalStorageClient'; +import 'semantic-ui-css/semantic.min.css'; window.addEventListener('load', async () => { const root = ReactDOM.createRoot( diff --git a/src/section_view.css b/src/section_view.css deleted file mode 100644 index 7b8a5c8..0000000 --- a/src/section_view.css +++ /dev/null @@ -1,168 +0,0 @@ - - -* { - box-sizing: border-box; -} - -html {font-size: 62.5%;} - - -.root { - display: flex; - background-color: rgb(95, 193, 208); - justify-content: center; - flex-direction: column; - min-height: 100vh; -} - - - -div { - border: 1px solid black; - border-collapse: collapse; - -} - - - - - - - -/* SECTION TITLE STYLES */ - - -.section-title { - flex-grow: 1; - display: flex; -} - -.section-title h1 { - font-size: 4rem; -} - -.section-title p { - font-size: 2rem; -} - -.section-title .revisions { -flex-grow: 1; -display: flex; - justify-content: center; - align-items: center; -} - -.section-title .text { - flex-grow: 9; - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; -} - - -/* CHORD PROGRESSION STYLES */ - - -.chords { - flex-grow: 2; - display: flex; - justify-content: space-evenly; - align-items: center; - flex-direction: row; -} - -.chords ol li{ - font-size: 7rem; - display: inline; - margin: 3rem; -} - - - -/* FILES STYLES */ - - -.files { - flex-grow: 3; - display: flex; - justify-content: space-around; - align-items: center; - flex-direction: row; -} - - -.files div { - display: inline; - margin: 3rem; - padding: 3rem; - border: 0.3rem solid rgb(0, 0, 0); - font-size: 3.5rem; -} - - - -.files span { - font-size: 3rem; -} - -.files span::first-letter { - font-size: 5rem; -} - - -/* STLYES FOR COMMENTS */ - - -.comments { - flex-grow: 3; - display: flex; - justify-content: flex-start; - align-items: flex-start; - flex-direction: column; - font-size: 2.5rem; -} - - -.comments span { - font-size: 7rem; - padding: 4rem; - margin-left: auto; - margin-right: auto; -} - -.comments p { - padding: 3rem 0; - padding-left: 3rem; -} - -.display-comments { - background-color: rgb(73, 229, 253); - margin-left: 5rem; -} - - - - - - -/* STYLES FOR SUBMITTING A COMMENT */ - - - -.submit { - flex-grow: 2; - display: flex; - justify-content: center; - align-items: center; -} - -.submit * { - margin: 5rem; -} - -.submit textarea { - width: 45%; - height: 80%; - background-color: rgb(73, 229, 253); -} From d2bdbf3e9cc9b261aca4361e82db355a99162950 Mon Sep 17 00:00:00 2001 From: Michael Kochell <6913320+mickmister@users.noreply.github.com> Date: Sat, 29 Jun 2024 15:02:55 -0400 Subject: [PATCH 08/11] rename Foo to SectionView --- src/App.tsx | 2 +- src/{Foo.tsx => SectionView.tsx} | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) rename src/{Foo.tsx => SectionView.tsx} (98%) diff --git a/src/App.tsx b/src/App.tsx index 73aeb62..3433884 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -5,7 +5,7 @@ import {GlobalStoreProvider} from './hooks/useGlobalStore'; import {IClient} from './client/IClient'; import {ClientProvider} from './hooks/useClient'; import {useMount} from './hooks/useMount'; -import SectionView from './Foo'; +import SectionView from './SectionView'; type AppProps = { projectId: string; diff --git a/src/Foo.tsx b/src/SectionView.tsx similarity index 98% rename from src/Foo.tsx rename to src/SectionView.tsx index b76387a..b52aa55 100644 --- a/src/Foo.tsx +++ b/src/SectionView.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import { Container, Header, Menu, Dropdown, Grid, Comment, Form, Button, List } from 'semantic-ui-react'; const SectionView = () => ( @@ -52,7 +51,8 @@ const SectionView = () => ( - + + Guitar.mp3 @@ -66,6 +66,7 @@ const SectionView = () => ( 23 comments + From 82cbee930f11193e4ae94b109997c38b3b9d2720 Mon Sep 17 00:00:00 2001 From: Alec Rollison <88508028+aelishRollo@users.noreply.github.com> Date: Sat, 6 Jul 2024 16:31:21 -0400 Subject: [PATCH 09/11] Implement as a modal --- src/ProjectView.tsx | 72 ++++++++++++++++ src/SectionView.tsx | 196 +++++++++++++++++++++++--------------------- 2 files changed, 173 insertions(+), 95 deletions(-) create mode 100644 src/ProjectView.tsx diff --git a/src/ProjectView.tsx b/src/ProjectView.tsx new file mode 100644 index 0000000..a295a63 --- /dev/null +++ b/src/ProjectView.tsx @@ -0,0 +1,72 @@ +import React, { useState } from 'react'; +import { Container, List, Icon } from 'semantic-ui-react'; + +interface Project { + id: string; + name: string; + sections?: Section[]; +} + +interface Section { + id: string; + name: string; + files?: File[]; +} + +interface File { + id: string; + name: string; + comments?: number; +} + +const ProjectView: React.FC = () => { + const [activeProject, setActiveProject] = useState(null); + + const handleProjectClick = (project: Project) => { + setActiveProject(project); + }; + + return ( + + {/* Project List */} + + handleProjectClick({ id: '1', name: 'Project 1' })}> + + + Project 1 + + + handleProjectClick({ + id: '2', name: 'Project 2', + sections: [ + { id: '1', name: 'Section 1', files: [{ id: '1', name: 'Bass.mp3', comments: 2 }] }, + { id: '2', name: 'Section 2' } + ] + })}> + + + Project 2 + + + + + Section 1 + Bass.mp3 + + + + + + Section 2 + + + + + + {/* Add more projects as needed */} + + + ); +}; + +export default ProjectView; diff --git a/src/SectionView.tsx b/src/SectionView.tsx index b52aa55..aa8732d 100644 --- a/src/SectionView.tsx +++ b/src/SectionView.tsx @@ -1,102 +1,108 @@ -import { Container, Header, Menu, Dropdown, Grid, Comment, Form, Button, List } from 'semantic-ui-react'; +import React, { useState } from 'react'; +import { Container, Header, Menu, Dropdown, Grid, Comment, Form, Button, List, Icon, Modal } from 'semantic-ui-react'; +import ProjectView from './ProjectView'; -const SectionView = () => ( - - {/* Menu */} - - - My section - - - - - Edit title - Edit Progression - Duplicate - Delete - - - - +const SectionView: React.FC = () => { + const [modalOpen, setModalOpen] = useState(false); - {/* Chord Progression */} - Progression: C Dm Em F + const handleOpen = () => setModalOpen(true); + const handleClose = () => setModalOpen(false); - {/* Grid Layout */} - - - - - - - - Bass.mp3 - 2 comments - - - - - - Guitar.mp3 - 23 comments - - - - - - Guitar.mp3 - 23 comments - - - - - - - - - - Guitar.mp3 - 23 comments - - - - - - Guitar.mp3 - 23 comments - - - - - - + return ( + + {/* Hamburger Menu */} + + + - {/* Comments Section */} - Comments for section - - - - - Dave - Great section! - - - - - - Matthews - Great section! - - - {/* Add more comments as needed */} - + {/* Modal for ProjectView */} + + Select a Project + + + + - {/* Comment Form */} - - - - - -); + {/* Main Content */} + + {/* Menu */} + + + My section + + + + + Edit title + Edit Progression + Duplicate + Delete + + + + + + {/* Chord Progression */} + Progression: C Dm Em F + + {/* Grid Layout */} + + + + + + + + Bass.mp3 + 2 comments + + + {/* Add more files as needed */} + + + + + + + + Guitar.mp3 + 23 comments + + + {/* Add more files as needed */} + + + + + + {/* Comments Section */} + Comments for section + + + + + Dave + Great section! + + + + + + Matthews + Great section! + + + {/* Add more comments as needed */} + + + {/* Comment Form */} + + + + + + + ); +}; export default SectionView; From 76292da31e570a40cf86debd3dad2e387fdf5941 Mon Sep 17 00:00:00 2001 From: Alec Rollison <88508028+aelishRollo@users.noreply.github.com> Date: Sat, 6 Jul 2024 16:33:19 -0400 Subject: [PATCH 10/11] Refactor to be a drop down rather than a modal --- src/SectionView.tsx | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/SectionView.tsx b/src/SectionView.tsx index aa8732d..866d81c 100644 --- a/src/SectionView.tsx +++ b/src/SectionView.tsx @@ -1,27 +1,31 @@ import React, { useState } from 'react'; -import { Container, Header, Menu, Dropdown, Grid, Comment, Form, Button, List, Icon, Modal } from 'semantic-ui-react'; +import { Container, Header, Menu, Dropdown, Grid, Comment, Form, Button, List, Icon } from 'semantic-ui-react'; import ProjectView from './ProjectView'; const SectionView: React.FC = () => { - const [modalOpen, setModalOpen] = useState(false); + const [dropdownOpen, setDropdownOpen] = useState(false); - const handleOpen = () => setModalOpen(true); - const handleClose = () => setModalOpen(false); + const handleDropdownToggle = () => { + setDropdownOpen(!dropdownOpen); + }; return ( {/* Hamburger Menu */} - - - - - {/* Modal for ProjectView */} - - Select a Project - + + + + } + open={dropdownOpen} + onClick={handleDropdownToggle} + > + - - + + {/* Main Content */} From f9636c6e053c47f02e3c09e3641b841e1f480084 Mon Sep 17 00:00:00 2001 From: Alec Rollison <88508028+aelishRollo@users.noreply.github.com> Date: Sat, 6 Jul 2024 16:42:53 -0400 Subject: [PATCH 11/11] Adjust hamburger menu positioning --- src/SectionView.tsx | 65 +++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/SectionView.tsx b/src/SectionView.tsx index 866d81c..0f5d75a 100644 --- a/src/SectionView.tsx +++ b/src/SectionView.tsx @@ -11,41 +11,42 @@ const SectionView: React.FC = () => { return ( - {/* Hamburger Menu */} - - - - } - open={dropdownOpen} - onClick={handleDropdownToggle} - > - - - - + + + {/* Hamburger Menu */} + + + + } + open={dropdownOpen} + onClick={handleDropdownToggle} + style={{ marginRight: '1rem' }} + > + + + + + + {/* Section Header */} + My section + + + {/* Ellipsis Menu */} + + + Edit title + Edit Progression + Duplicate + Delete + + + {/* Main Content */} - {/* Menu */} - - - My section - - - - - Edit title - Edit Progression - Duplicate - Delete - - - - - {/* Chord Progression */} Progression: C Dm Em F
- {error} -
- Loading -
+ {error} +
+ Loading +