Skip to content

Commit

Permalink
Port Pronunciations to use redux-toolkit (#2753)
Browse files Browse the repository at this point in the history
  • Loading branch information
imnasnainaec authored Nov 8, 2023
1 parent fa59f6f commit 6b800c0
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 76 deletions.
11 changes: 7 additions & 4 deletions src/components/Pronunciations/AudioPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useTranslation } from "react-i18next";
import { ButtonConfirmation } from "components/Dialogs";
import {
playing,
reset,
resetPronunciations,
} from "components/Pronunciations/Redux/PronunciationsActions";
import { PronunciationsStatus } from "components/Pronunciations/Redux/PronunciationsReduxTypes";
import { StoreState } from "types";
Expand All @@ -38,8 +38,8 @@ const useStyles = makeStyles((theme: Theme) =>
export default function AudioPlayer(props: PlayerProps): ReactElement {
const isPlaying = useAppSelector(
(state: StoreState) =>
state.pronunciationsState.payload === props.fileName &&
state.pronunciationsState.type === PronunciationsStatus.Playing
state.pronunciationsState.fileName === props.fileName &&
state.pronunciationsState.status === PronunciationsStatus.Playing
);

const [audio] = useState<HTMLAudioElement>(new Audio(props.pronunciationUrl));
Expand All @@ -48,7 +48,10 @@ export default function AudioPlayer(props: PlayerProps): ReactElement {

const classes = useStyles();
const dispatch = useAppDispatch();
const dispatchReset = useCallback(() => dispatch(reset()), [dispatch]);
const dispatchReset = useCallback(
() => dispatch(resetPronunciations()),
[dispatch]
);
const { t } = useTranslation();

useEffect(() => {
Expand Down
18 changes: 8 additions & 10 deletions src/components/Pronunciations/RecorderIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";

import {
recording,
reset,
resetPronunciations,
} from "components/Pronunciations/Redux/PronunciationsActions";
import { PronunciationsStatus } from "components/Pronunciations/Redux/PronunciationsReduxTypes";
import { StoreState } from "types";
Expand All @@ -23,9 +23,12 @@ interface RecorderIconProps {
}

export default function RecorderIcon(props: RecorderIconProps): ReactElement {
const pronunciationsState = useAppSelector(
(state: StoreState) => state.pronunciationsState
const isRecording = useAppSelector(
(state: StoreState) =>
state.pronunciationsState.status === PronunciationsStatus.Recording &&
state.pronunciationsState.wordId === props.wordId
);

const dispatch = useAppDispatch();
const { t } = useTranslation();

Expand All @@ -43,7 +46,7 @@ export default function RecorderIcon(props: RecorderIconProps): ReactElement {
}
function toggleIsRecordingToFalse(): void {
props.stopRecording();
dispatch(reset());
dispatch(resetPronunciations());
}

function handleTouchStart(): void {
Expand Down Expand Up @@ -77,12 +80,7 @@ export default function RecorderIcon(props: RecorderIconProps): ReactElement {
tabIndex={-1}
>
<FiberManualRecord
className={
pronunciationsState.type === PronunciationsStatus.Recording &&
pronunciationsState.payload === props.wordId
? classes.iconPress
: classes.iconRelease
}
className={isRecording ? classes.iconPress : classes.iconRelease}
id={recordIconId}
/>
</IconButton>
Expand Down
29 changes: 14 additions & 15 deletions src/components/Pronunciations/Redux/PronunciationsActions.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import { Action, PayloadAction } from "@reduxjs/toolkit";

import {
PronunciationsAction,
PronunciationsStatus,
} from "components/Pronunciations/Redux/PronunciationsReduxTypes";
resetAction,
setPlayingAction,
setRecordingAction,
} from "components/Pronunciations/Redux/PronunciationsReducer";

// Action Creation Functions

export function playing(payload: string): PronunciationsAction {
return {
type: PronunciationsStatus.Playing,
payload,
};
export function playing(fileName: string): PayloadAction {
return setPlayingAction(fileName);
}

export function recording(payload: string): PronunciationsAction {
return {
type: PronunciationsStatus.Recording,
payload,
};
export function recording(wordId: string): PayloadAction {
return setRecordingAction(wordId);
}

export function reset(): PronunciationsAction {
return { type: PronunciationsStatus.Default };
export function resetPronunciations(): Action {
return resetAction();
}
47 changes: 27 additions & 20 deletions src/components/Pronunciations/Redux/PronunciationsReducer.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
import { createSlice } from "@reduxjs/toolkit";

import {
defaultState,
PronunciationsAction,
PronunciationsStatus,
PronunciationsState,
} from "components/Pronunciations/Redux/PronunciationsReduxTypes";
import { StoreAction, StoreActionTypes } from "rootActions";
import { StoreActionTypes } from "rootActions";

const pronunciationsSlice = createSlice({
name: "pronunciationsState",
initialState: defaultState,
reducers: {
resetAction: () => defaultState,
setPlayingAction: (state, action) => {
state.fileName = action.payload;
state.status = PronunciationsStatus.Playing;
state.wordId = "";
},
setRecordingAction: (state, action) => {
state.fileName = "";
state.status = PronunciationsStatus.Recording;
state.wordId = action.payload;
},
},
extraReducers: (builder) =>
builder.addCase(StoreActionTypes.RESET, () => defaultState),
});

export const { resetAction, setPlayingAction, setRecordingAction } =
pronunciationsSlice.actions;

export const pronunciationsReducer = (
state: PronunciationsState = defaultState,
action: StoreAction | PronunciationsAction
): PronunciationsState => {
switch (action.type) {
case PronunciationsStatus.Playing:
return { ...defaultState, ...action };
case PronunciationsStatus.Recording:
return { ...defaultState, ...action };
case PronunciationsStatus.Default:
return defaultState;
case StoreActionTypes.RESET:
return defaultState;
default:
return state;
}
};
export default pronunciationsSlice.reducer;
17 changes: 7 additions & 10 deletions src/components/Pronunciations/Redux/PronunciationsReduxTypes.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
export enum PronunciationsStatus {
Default = "DEFAULT",
Inactive = "INACTIVE",
Playing = "PLAYING",
Recording = "RECORDING",
}

export interface PronunciationsAction {
type: PronunciationsStatus;
payload?: string;
}

export interface PronunciationsState {
type: PronunciationsStatus;
payload: string;
fileName: string;
status: PronunciationsStatus;
wordId: string;
}

export const defaultState: PronunciationsState = {
type: PronunciationsStatus.Default,
payload: "",
fileName: "",
status: PronunciationsStatus.Inactive,
wordId: "",
};
31 changes: 15 additions & 16 deletions src/components/Pronunciations/tests/AudioRecorder.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { StyledEngineProvider, ThemeProvider } from "@mui/material/styles";
import { Provider } from "react-redux";
import renderer from "react-test-renderer";
import { ReactTestRenderer, act, create } from "react-test-renderer";
import configureMockStore from "redux-mock-store";

import "tests/reactI18nextMock";
Expand All @@ -11,32 +11,31 @@ import RecorderIcon, {
recordIconId,
} from "components/Pronunciations/RecorderIcon";
import {
PronunciationsState,
defaultState as pronunciationsState,
PronunciationsStatus,
} from "components/Pronunciations/Redux/PronunciationsReduxTypes";
import { StoreState } from "types";
import theme from "types/theme";

jest.mock("components/Pronunciations/Recorder");

let testRenderer: renderer.ReactTestRenderer;
let testRenderer: ReactTestRenderer;

const createMockStore = configureMockStore();
const mockStore = createMockStore({ pronunciationsState });
function mockRecordingState(wordId: string): {
pronunciationsState: Partial<PronunciationsState>;
} {
function mockRecordingState(wordId: string): Partial<StoreState> {
return {
pronunciationsState: {
type: PronunciationsStatus.Recording,
payload: wordId,
fileName: "",
status: PronunciationsStatus.Recording,
wordId,
},
};
}

beforeAll(() => {
renderer.act(() => {
testRenderer = renderer.create(
act(() => {
testRenderer = create(
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<Provider store={mockStore}>
Expand All @@ -52,8 +51,8 @@ describe("Pronunciations", () => {
test("pointerDown and pointerUp", () => {
const mockStartRecording = jest.fn();
const mockStopRecording = jest.fn();
renderer.act(() => {
testRenderer = renderer.create(
act(() => {
testRenderer = create(
<StyledEngineProvider injectFirst>
<ThemeProvider theme={theme}>
<Provider store={mockStore}>
Expand All @@ -78,8 +77,8 @@ describe("Pronunciations", () => {
});

test("default style is iconRelease", () => {
renderer.act(() => {
testRenderer = renderer.create(
act(() => {
testRenderer = create(
<ThemeProvider theme={theme}>
<StyledEngineProvider>
<Provider store={mockStore}>
Expand All @@ -96,8 +95,8 @@ describe("Pronunciations", () => {
test("style depends on pronunciations state", () => {
const wordId = "1";
const mockStore2 = createMockStore(mockRecordingState(wordId));
renderer.act(() => {
testRenderer = renderer.create(
act(() => {
testRenderer = create(
<ThemeProvider theme={theme}>
<StyledEngineProvider>
<Provider store={mockStore2}>
Expand Down
2 changes: 1 addition & 1 deletion src/rootReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import goalsReducer from "components/GoalTimeline/Redux/GoalReducer";
import loginReducer from "components/Login/Redux/LoginReducer";
import { projectReducer } from "components/Project/ProjectReducer";
import exportProjectReducer from "components/ProjectExport/Redux/ExportProjectReducer";
import { pronunciationsReducer } from "components/Pronunciations/Redux/PronunciationsReducer";
import pronunciationsReducer from "components/Pronunciations/Redux/PronunciationsReducer";
import { treeViewReducer } from "components/TreeView/Redux/TreeViewReducer";
import { characterInventoryReducer } from "goals/CharacterInventory/Redux/CharacterInventoryReducer";
import mergeDupStepReducer from "goals/MergeDuplicates/Redux/MergeDupsReducer";
Expand Down

0 comments on commit 6b800c0

Please sign in to comment.