Skip to content

Commit

Permalink
first page load bug fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
jekrch committed Nov 4, 2024
1 parent e178145 commit 0a18d4d
Show file tree
Hide file tree
Showing 8 changed files with 544 additions and 75 deletions.
332 changes: 332 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"start": "vite --port 3000",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
"preview": "vite preview",
"predeploy": "npm run build",
"deploy": "gh-pages -d dist"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.36",
Expand Down Expand Up @@ -41,6 +43,7 @@
"eslint": "^9.13.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"gh-pages": "^6.2.0",
"globals": "^15.11.0",
"typescript": "~5.6.2",
"typescript-eslint": "^8.11.0",
Expand Down
2 changes: 1 addition & 1 deletion src/components/Layout/HeaderComponent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ export const HeaderComponent = () => {
}

const renderProgression = () => {
return state.chordPianoSet.map((piano, i) => {
return state.chordPianoSet?.map((piano, i) => {
return (
<div key={"ci-" + piano.id}>
<Link
Expand Down
40 changes: 32 additions & 8 deletions src/components/PianoBoardComponent.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React, { useEffect } from "react"
import "../styles/Piano.css"
import React, { useEffect, useState, useLayoutEffect } from "react"
import { useAppContext } from "../components/context/AppContext"
import { getProgressionCode } from "../utils/chordCodeHandler"
import { ChordPianoComponent } from "../components/ChordPianoComponent"
Expand All @@ -8,6 +7,25 @@ import { useHistory } from "react-router-dom"
export const PianoBoardComponent = () => {
const { state, dispatch } = useAppContext()
const history = useHistory()
const [isInitialized, setIsInitialized] = useState(false)
const [refresh, setRefresh] = useState(0)

// Handle initial load and URL changes
useLayoutEffect(() => {
const handleInitialLoad = () => {
const newParams = history.location.search + history.location.hash
if (!isInitialized && newParams) {
dispatch({
type: "BUILD_PROG_FROM_CODE",
payload: newParams
})
setIsInitialized(true)
setRefresh(prev => prev + 1)
}
}

handleInitialLoad()
}, [history.location.search, history.location.hash, isInitialized, dispatch])

// Handle URL changes and chord building
useEffect(() => {
Expand All @@ -19,10 +37,16 @@ export const PianoBoardComponent = () => {
type: "BUILD_PROG_FROM_CODE",
payload: newParams
})
setRefresh(prev => prev + 1)
}
}, [history.location.search, history.location.hash, state.building, dispatch])

// Update URL when state changes
useEffect(() => {
if (!state.chordPianoSet) {
return
}

const currentCode = getProgressionCode(state)
const newParams = history.location.search + history.location.hash

Expand All @@ -31,14 +55,14 @@ export const PianoBoardComponent = () => {
search: currentCode
})
}
}, [state])
}, [state, history])

const renderChordPianoSet = () => {
return state.chordPianoSet.map((chordPiano) => (
<div key={chordPiano.id}>
return state.chordPianoSet?.map((chordPiano) => (
<div key={`wrapper-${chordPiano.id}-${refresh}`}>
<ChordPianoComponent
id={`piano-${chordPiano.id}`}
key={`piano-${chordPiano.id}`}
key={`piano-${chordPiano.id}-${refresh}`}
className="row chordPianoComponent"
pianoComponentId={Number(chordPiano.id)}
history={history}
Expand All @@ -49,8 +73,8 @@ export const PianoBoardComponent = () => {
}

return (
<div key="pianoBoard" className="pianoBoard">
{state.chordPianoSet.length > 0 ? (
<div key={`pianoBoard-${refresh}`} className="pianoBoard">
{state.chordPianoSet?.length ?? 0 > 0 ? (
<>
{renderChordPianoSet()}
<div className="pianoBoardGutter" />
Expand Down
162 changes: 130 additions & 32 deletions src/components/PianoComponent.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext } from "react"
import React, { useEffect, useRef } from "react"
import "../styles/Piano.css"
import { Key } from "./Key"
import { useAppContext, getPianoById, getProgKey } from "./context/AppContext"
Expand All @@ -8,17 +8,46 @@ import { getChordNumeral } from "../utils/numeralHelper"
import { playPiano } from "../utils/synthPlayer"
import PropTypes from "prop-types"

export const PianoComponent = ({ pianoComponentId }) => {
export const PianoComponent = ({ pianoComponentId, forceUpdate }) => {
const { state, dispatch } = useAppContext()
const pianoId = pianoComponentId
const mountedRef = useRef(false)

const handleClick = (note, noteNumber, octave) => {
useEffect(() => {
if (!mountedRef.current) {
mountedRef.current = true
// Force a re-render of the piano keys on mount
const piano = getPianoById(state, pianoId)
if (piano) {
dispatch({
type: "REFRESH_PIANO",
id: pianoId,
payload: piano
})
}
}
}, [pianoId, state, dispatch])

const noteLetter = getNoteLetter("C", noteNumber)
// Force update when parent signals
useEffect(() => {
if (forceUpdate) {
const piano = getPianoById(state, pianoId)
if (piano) {
dispatch({
type: "REFRESH_PIANO",
id: pianoId,
payload: piano
})
}
}
}, [forceUpdate, pianoId, state, dispatch])

var selectedKey = {}
selectedKey.noteLetter = noteLetter
selectedKey.octave = octave
const handleClick = (note, noteNumber, octave) => {
const noteLetter = getNoteLetter("C", noteNumber)
const selectedKey = {
noteLetter,
octave
}
dispatch({
type: "UPDATE_KEY",
id: pianoId,
Expand All @@ -37,28 +66,28 @@ export const PianoComponent = ({ pianoComponentId }) => {
playPiano(dispatch, state, pianoId)
}

const getNumeralChord = (chord) => {
let piano = getPianoById(state, pianoId)
let key = getProgKey(state);
const getNumeralChord = () => {
const piano = getPianoById(state, pianoId)
const key = getProgKey(state)
return getChordNumeral(key, piano.selectedChord)
}

const renderPiano = () => {
let piano = getPianoById(state, pianoId).piano
return piano.map((octave, i) => {
return octave.map((pianoKey) => {
pianoKey.octave = i
return (
<Key
key={`${pianoKey.note}-${i}`}
pianoKey={pianoKey}
handleClick={() =>
handleClick(pianoKey.note, pianoKey.noteNumber, pianoKey.octave)
}
/>
)
})
})
const piano = getPianoById(state, pianoId)?.piano || []
return piano.map((octave, i) =>
octave.map((pianoKey) => ({
...pianoKey,
octave: i,
key: `${pianoKey.note}-${i}-${forceUpdate}`,
handleClick: () => handleClick(pianoKey.note, pianoKey.noteNumber, i)
}))
).flat().map(pianoKey => (
<Key
key={pianoKey.key}
pianoKey={pianoKey}
handleClick={pianoKey.handleClick}
/>
))
}

return (
Expand All @@ -67,14 +96,14 @@ export const PianoComponent = ({ pianoComponentId }) => {
<button
type="button"
className="piano-play-button"
onClick={() => handlePlayClick()}
></button>
onClick={handlePlayClick}
/>
<div className="pianoBox">
<button
type="button"
className="close pianoCloseButton"
aria-label="Close"
onClick={() => handleClickRemovePiano()}
onClick={handleClickRemovePiano}
>
<span aria-hidden="true">&times;</span>
</button>
Expand All @@ -85,19 +114,88 @@ export const PianoComponent = ({ pianoComponentId }) => {
type="button"
className="close pianoCloseButtonMobile"
aria-label="Close"
onClick={() => handleClickRemovePiano()}
onClick={handleClickRemovePiano}
>
<span className="mobileClosedBtnText">&times;</span>
</button>

</div>
</div>
<div className="pianoRomanNumeral">{getNumeralChord(pianoId)}
<div className="pianoRomanNumeral">
{getNumeralChord()}
</div>
</>
)
}

PianoComponent.propTypes = {
pianoComponentId: PropTypes.number.isRequired
pianoComponentId: PropTypes.number.isRequired,
forceUpdate: PropTypes.number
}

export const PianoBoardComponent = () => {
const { state, dispatch } = useAppContext()
const history = useHistory()
const [refresh, setRefresh] = useState(0)
const initialLoadRef = useRef(false)

// Handle initial load
useEffect(() => {
if (!initialLoadRef.current) {
initialLoadRef.current = true
const newParams = history.location.search + history.location.hash
if (newParams) {
dispatch({
type: "BUILD_PROG_FROM_CODE",
payload: newParams
})
setRefresh(prev => prev + 1)
}
}
}, [dispatch, history.location])

// Handle URL changes
useEffect(() => {
const currentCode = getProgressionCode(state)
const newParams = history.location.search + history.location.hash

if (!state.building && currentCode !== newParams) {
dispatch({
type: "BUILD_PROG_FROM_CODE",
payload: newParams
})
setRefresh(prev => prev + 1)
}
}, [history.location.search, history.location.hash, state.building, dispatch])

const renderChordPianoSet = () => {
return state.chordPianoSet?.map((chordPiano) => (
<div key={`wrapper-${chordPiano.id}-${refresh}`}>
<ChordPianoComponent
id={`piano-${chordPiano.id}`}
pianoComponentId={Number(chordPiano.id)}
forceUpdate={refresh}
history={history}
/>
<div className="pianoStrip" />
</div>
))
}

return (
<div className="pianoBoard">
{state.chordPianoSet?.length ? (
<>
{renderChordPianoSet()}
<div className="pianoBoardGutter" />
</>
) : (
<div className="introBody">
<div className="introText">
welcome to chord buildr<br/>
use the controls above to get started
</div>
</div>
)}
</div>
)
}
Loading

0 comments on commit 0a18d4d

Please # to comment.