Skip to content

Commit

Permalink
Add chordType selector (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
cyrilgourgouillon committed Dec 2, 2023
1 parent 6d13f18 commit d631a61
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 54 deletions.
51 changes: 51 additions & 0 deletions src/components/ChordTypeSelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { AbsoluteCenter, Box, Button, Divider } from '@chakra-ui/react';
import { ChordType, chordTypes as allChords } from '../config';
import { useChordSettingsContext } from '../hooks';

export const ChordSelector = () => {
const { availableChordTypes, setAvailableChordTypes } = useChordSettingsContext();

const handleRemoveChordType = (chord: ChordType) => {
if (availableChordTypes.length !== 1) {
setAvailableChordTypes(availableChordTypes.filter((n) => n !== chord));
}
};

const handleAddChordType = (chord: ChordType) => {
setAvailableChordTypes([chord, ...availableChordTypes]);
};

return (
<>
<Box position="relative" padding="2">
<Divider />
<AbsoluteCenter bg="white" px="4">
Chords selector
</AbsoluteCenter>
</Box>
<div className="flex flex-row flex-wrap justify-center gap-1">
{allChords.map((chord) => {
const chordIsActive = availableChordTypes.includes(chord);
return (
<Button
key={chord}
variant="outline"
size="sm"
isActive={chordIsActive}
colorScheme={chordIsActive ? 'green' : 'gray'}
onClick={() => {
if (chordIsActive) {
handleRemoveChordType(chord);
} else {
handleAddChordType(chord);
}
}}
>
{chord}
</Button>
);
})}
</div>
</>
);
};
2 changes: 2 additions & 0 deletions src/components/ChordsSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { MdBuild } from "react-icons/md";
import { CHORDS_LIST_MIN, CHORDS_LIST_MAX } from "../config/constants";
import { AutoSkipper } from "./AutoSkipper";
import { useChordSettingsContext } from "../hooks";
import { ChordSelector } from "./ChordTypeSelector";

export const ChordsSettings = () => {
const {
Expand Down Expand Up @@ -57,6 +58,7 @@ export const ChordsSettings = () => {
>
Toggle shape complexity
</Button>
<ChordSelector />
<AutoSkipper />
</div>
</PopoverBody>
Expand Down
8 changes: 4 additions & 4 deletions src/components/NoteSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ export const NoteSelector = () => {
const { availableNotes, setAvailableNotes } = useNoteSettingsContext();

const handleRemoveNote = (note: Note) => {
console.log('remove');
setAvailableNotes(availableNotes.filter((n) => n !== note));
if (availableNotes.length !== 1) {
setAvailableNotes(availableNotes.filter((n) => n !== note));
}
};

const handleAddNote = (note: Note) => {
console.log('add');
setAvailableNotes([note, ...availableNotes]);
};

Expand All @@ -20,7 +20,7 @@ export const NoteSelector = () => {
<Box position="relative" padding="2">
<Divider />
<AbsoluteCenter bg="white" px="4">
Notes selector
Note selector
</AbsoluteCenter>
</Box>
<div className="flex flex-row flex-wrap justify-center gap-1">
Expand Down
6 changes: 3 additions & 3 deletions src/config/Chords.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { Note } from ".";

export enum ChordsType {
Major = "",
Major = "M",
Minor = "m",
MajorSeventh = "maj7",
MinorSeventh = "min7",
}

export type ChordType = keyof typeof ChordsType;
export type ChordType = '' | 'm' | 'maj7' | 'min7';

export const chords = Object.values(ChordsType) as unknown as ChordType[];
export const chordTypes = Object.values(ChordsType) as ChordType[];

export type Chord = {
note: Note;
Expand Down
47 changes: 18 additions & 29 deletions src/contexts/ChordContext.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { createContext, useCallback, useEffect, useState } from "react";
import { DEFAULT_NUMBER_OF_CHORD } from "../config/constants";
import {
getListOfRandomChords,
getRandomNoteFromCaged,
isValidChordCountList,
} from "../services";
import { CagedType, Chord } from "../config";
import { useSpeedContext } from "../hooks";
import { Dispatch, SetStateAction, createContext, useCallback, useEffect, useState } from 'react';
import { DEFAULT_NUMBER_OF_CHORD } from '../config/constants';
import { getListOfRandomChords, getRandomNoteFromCaged, isValidChordCountList } from '../services';
import { CagedType, Chord, ChordType, chordTypes as allChordTypes } from '../config';
import { useSpeedContext } from '../hooks';

interface ChordSettingsContextProps {
chords: Chord[];
availableChordTypes: ChordType[];
setAvailableChordTypes: Dispatch<SetStateAction<ChordType[]>>;
numberOfChordDisplayed: number;
isShapeVisible: boolean;
cagedPosition: CagedType;
Expand All @@ -18,25 +16,14 @@ interface ChordSettingsContextProps {
toggleShapeVisible: () => void;
}

export const ChordSettingsContext = createContext<
ChordSettingsContextProps | undefined
>(undefined);
export const ChordSettingsContext = createContext<ChordSettingsContextProps | undefined>(undefined);

export const ChordSettingsContextProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const [chords, setChords] = useState<Chord[]>(
getListOfRandomChords(DEFAULT_NUMBER_OF_CHORD)
);
const [numberOfChordDisplayed, setNumberOfChordDisplayed] = useState(
DEFAULT_NUMBER_OF_CHORD
);
export const ChordSettingsContextProvider = ({ children }: { children: React.ReactNode }) => {
const [availableChordTypes, setAvailableChordTypes] = useState<ChordType[]>([...allChordTypes]);
const [chords, setChords] = useState<Chord[]>(getListOfRandomChords(DEFAULT_NUMBER_OF_CHORD, availableChordTypes));
const [numberOfChordDisplayed, setNumberOfChordDisplayed] = useState(DEFAULT_NUMBER_OF_CHORD);
const [isShapeVisible, setIsShapeVisible] = useState(false);
const [cagedPosition, setCagedPosition] = useState<CagedType>(
getRandomNoteFromCaged()
);
const [cagedPosition, setCagedPosition] = useState<CagedType>(getRandomNoteFromCaged());

const { speed, secondsElapsed, resetSecondsElapsed } = useSpeedContext();

Expand All @@ -55,9 +42,9 @@ export const ChordSettingsContextProvider = ({
};

const getRandomChordsOnClick = useCallback(() => {
setChords(getListOfRandomChords(numberOfChordDisplayed));
setChords(getListOfRandomChords(numberOfChordDisplayed, availableChordTypes));
setCagedPosition(getRandomNoteFromCaged());
}, [numberOfChordDisplayed]);
}, [numberOfChordDisplayed, availableChordTypes]);

useEffect(() => {
if (speed && speed / 1000 === secondsElapsed) {
Expand All @@ -68,13 +55,15 @@ export const ChordSettingsContextProvider = ({

useEffect(() => {
resetSecondsElapsed();
// eslint-disable-next-line react-hooks/exhaustive-deps
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [speed]);

return (
<ChordSettingsContext.Provider
value={{
chords,
availableChordTypes,
setAvailableChordTypes,
numberOfChordDisplayed,
isShapeVisible,
cagedPosition,
Expand Down
6 changes: 3 additions & 3 deletions src/contexts/NoteContext.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Dispatch, SetStateAction, createContext, useCallback, useEffect, useState } from "react";
import { DEFAULT_NUMBER_OF_NOTE } from "../config/constants";
import {
getListOfRandomNotesOf,
getRandomString,
isValidNoteCountList,
getListOfRandomNotes,
} from "../services";
import { GuitarString, Note, notes as allNotes } from "../config";
import { useSpeedContext } from "../hooks";
Expand Down Expand Up @@ -31,7 +31,7 @@ export const NoteSettingsContextProvider = ({
}) => {
const [availableNotes, setAvailableNotes] = useState<Note[]>([...allNotes]);
const [notes, setNotes] = useState<Note[]>(
getListOfRandomNotesOf(availableNotes, DEFAULT_NUMBER_OF_NOTE)
getListOfRandomNotes(DEFAULT_NUMBER_OF_NOTE, availableNotes)
);
const [numberOfNoteDisplayed, setNumberOfNoteDisplayed] = useState(
DEFAULT_NUMBER_OF_NOTE
Expand All @@ -58,7 +58,7 @@ export const NoteSettingsContextProvider = ({
};

const getRandomNotesOnClick = useCallback(() => {
setNotes(getListOfRandomNotesOf(availableNotes, numberOfNoteDisplayed));
setNotes(getListOfRandomNotes(numberOfNoteDisplayed, availableNotes));
setGuitarString(getRandomString());
}, [availableNotes, numberOfNoteDisplayed]);

Expand Down
14 changes: 7 additions & 7 deletions src/services/chordService.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { getRandomNote } from "./";
import { Chord, ChordType, chords } from "../config";
import { Chord, ChordType, chordTypes } from "../config";
import { getRandomItemFrom } from "../utils/random";
import { CHORDS_LIST_MAX, CHORDS_LIST_MIN } from "../config/constants";

export const getRandomChordType = (): ChordType => {
return getRandomItemFrom(chords);
export const getRandomChordType = (allChordTypes?: ChordType[]): ChordType => {
return getRandomItemFrom(allChordTypes ?? chordTypes);
};

export const getRandomChord = (): Chord => {
return { note: getRandomNote(), chordType: getRandomChordType() } as Chord;
export const getRandomChord = (allChordTypes?: ChordType[]): Chord => {
return { note: getRandomNote(), chordType: getRandomChordType(allChordTypes)} as Chord;
};

export const chordToString = (chord: Chord): string => {
return `${chord.note}${chord.chordType}`;
}

export const getListOfRandomChords = (count: number): Chord[] => {
export const getListOfRandomChords = (count: number, allChordTypes?: ChordType[]): Chord[] => {
const randomChords: Chord[] = [];
for(let i = 0; i < count; i++) {
randomChords.push(getRandomChord());
randomChords.push(getRandomChord(allChordTypes));
}
return randomChords;
};
Expand Down
10 changes: 2 additions & 8 deletions src/services/noteService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,8 @@ import { NOTES_LIST_MAX, NOTES_LIST_MIN } from "../config/constants";
import { getRandomItemFrom } from "../utils/random";
import { shuffle } from "../utils/shuffle";

export const getListOfRandomNotes = (count: number): Note[] => {
const randomNotes = shuffle(notes);

return randomNotes.slice(undefined, count);
};

export const getListOfRandomNotesOf = (allNotes: Note[], count: number): Note[] => {
const randomNotes = shuffle(allNotes);
export const getListOfRandomNotes = (count: number, allNotes?: Note[]): Note[] => {
const randomNotes = shuffle(allNotes ?? notes);

return randomNotes.slice(undefined, count);
};
Expand Down

0 comments on commit d631a61

Please sign in to comment.