Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/improve phrase #1513

Merged
merged 34 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
8786414
create API method to improvePhrase using gpt
tomivm Apr 20, 2023
bb5bcbe
dispatch improvePhrase on changeOutput
tomivm Apr 20, 2023
dfd255d
Merge branch 'master' into feature/improve-phrase
tomivm Jun 16, 2023
b5fcccc
Implement an action to change improved phrase
tomivm Jun 21, 2023
2646a02
Implement change improved phrase reducer
tomivm Jun 21, 2023
011249d
Add UI to Improve Phrase feature
tomivm Jun 21, 2023
5de180b
add state to enable and disable improve Phrase
tomivm Jun 22, 2023
078b5cd
Only dispatch improvePhrase wen feature is enabled
tomivm Jun 22, 2023
03c979a
Add item to Navigation settings to enable the Improve Phrase feature
tomivm Jun 22, 2023
78e7051
Show Improve Phrase components only when it is enabled
tomivm Jun 22, 2023
bd245d7
fix Proptype on improvePhraseControls
tomivm Jun 22, 2023
d60798c
Merge remote-tracking branch 'cboard-org/master' into feature/improve…
tomivm Jun 22, 2023
282c537
Add improvedPhrase to the initial state of the test
tomivm Jun 22, 2023
53ec967
Update App reducer test to support improvePhrase active setting
tomivm Jun 22, 2023
cd5eb3d
Test changeOutput action like a thunk
tomivm Jun 22, 2023
c973c09
Merge branch 'master' into feature/improve-phrase
tomivm Aug 10, 2023
a761494
Allow use improve phrase feature only for premium users
tomivm Aug 10, 2023
f65dd99
Pass the app language to gpt endpoint in order to avoid wrong results
tomivm Aug 10, 2023
301ed3f
remove console logs
tomivm Aug 11, 2023
e2c099b
Avoid disabling features for subscribers and users in a free country
tomivm Aug 11, 2023
ecb4741
Merge branch 'master' into feature/improve-phrase
tomivm Aug 28, 2023
a731132
Add new UI
tomivm Aug 28, 2023
f80e960
Remove old UI
tomivm Aug 28, 2023
05b8a75
Add divider on settings
tomivm Aug 28, 2023
dd923bd
Avoid render the ImprovePhraseOutput when feature is disabled
tomivm Aug 29, 2023
46a37ca
Change bg color of the improve phrase output
tomivm Aug 29, 2023
a0c7a47
Use horizontally scroll on text overflow
tomivm Sep 1, 2023
2d033a5
Cancel old requests before a new request to improve the phrase
tomivm Sep 1, 2023
be22d9b
Fix proptypes
tomivm Sep 1, 2023
16961a1
Replace console log by console error
tomivm Sep 1, 2023
a3d319a
Use camel case for toggleImprovePhraseActive function name
tomivm Sep 12, 2023
285b18b
Avoid confusions on names inside improvePhrase function
tomivm Sep 12, 2023
bb67888
Remove wrong comment
tomivm Sep 12, 2023
6202ca2
remove unnecessary component
tomivm Sep 12, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/api/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { isAndroid } from '../cordova-util';

const BASE_URL = API_URL;
const LOCAL_COMMUNICATOR_ID = 'cboard_default';
export let improvePhraseAbortController;

const getUserData = () => {
const store = getStore();
Expand Down Expand Up @@ -626,6 +627,32 @@ class API {
return data;
}
}

async improvePhrase({ phrase, language }) {
const authToken = getAuthToken();
if (!(authToken && authToken.length)) {
throw new Error('Need to be authenticated to perform this request');
}

try {
const headers = {
Authorization: `Bearer ${authToken}`
};
improvePhraseAbortController = new AbortController();
const { data } = await this.axiosInstance.post(
`/gpt/edit`,
{ phrase, language },
{
headers,
signal: improvePhraseAbortController.signal
}
);
return data;
} catch (error) {
if (error.message !== 'canceled') console.error(error);
return { phrase: '' };
}
}
}

const API_INSTANCE = new API({});
Expand Down
3 changes: 2 additions & 1 deletion src/components/App/App.reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ const initialState = {
quickUnlockActive: false,
removeOutputActive: false,
vocalizeFolders: false,
liveMode: false
liveMode: false,
improvePhraseActive: false
},
symbolsSettings: {
arasaacActive: false
Expand Down
40 changes: 21 additions & 19 deletions src/components/App/__tests__/App.reducer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
FINISH_FIRST_VISIT,
UPDATE_CONNECTIVITY,
UPDATE_DISPLAY_SETTINGS,
UPDATE_NAVIGATION_SETTINGS,
UPDATE_NAVIGATION_SETTINGS
} from '../App.constants';
import appReducer from '../App.reducer';

Expand All @@ -24,9 +24,9 @@ describe('reducer', () => {
communicatorTour: {
isCommBoardsEnabled: true,
isPublicBoardsEnabled: true,
isAllMyBoardsEnabled: true,
isAllMyBoardsEnabled: true
},
isAnalyticsTourEnabled: true,
isAnalyticsTourEnabled: true
},
displaySettings: {
uiSize: DISPLAY_SIZE_STANDARD,
Expand All @@ -35,7 +35,7 @@ describe('reducer', () => {
hideOutputActive: false,
increaseOutputButtons: false,
labelPosition: 'Below',
darkThemeActive: false,
darkThemeActive: false
},
navigationSettings: {
active: false,
Expand All @@ -47,11 +47,12 @@ describe('reducer', () => {
quickUnlockActive: false,
removeOutputActive: false,
vocalizeFolders: false,
improvePhraseActive: false
},
symbolsSettings: {
arasaacActive: false,
arasaacActive: false
},
userData: {},
userData: {}
};
uData = { name: 'martin bedouret', email: '[email protected]' };
mockApp = {
Expand All @@ -62,7 +63,7 @@ describe('reducer', () => {
labelPosition: 'Below',
fontFamily: DEFAULT_FONT_FAMILY,
fontSize: 'Standard',
darkThemeActive: false,
darkThemeActive: false
},
isConnected: true,
isFirstVisit: false,
Expand All @@ -76,8 +77,9 @@ describe('reducer', () => {
quickUnlockActive: false,
removeOutputActive: false,
vocalizeFolders: false,
improvePhraseActive: false
},
userData: uData,
userData: uData
};
});
it('should return the initial state', () => {
Expand All @@ -86,57 +88,57 @@ describe('reducer', () => {
it('should handle login ', () => {
const login = {
type: LOGIN_SUCCESS,
payload: uData,
payload: uData
};
expect(appReducer(initialState, login)).toEqual({
...initialState,
userData: uData,
isFirstVisit: false,
isFirstVisit: false
});
});
it('should handle logout', () => {
const logout = {
type: LOGOUT,
type: LOGOUT
};
expect(appReducer(initialState, logout)).toEqual(initialState);
});
it('should handle updateDisplaySettings', () => {
const updateDisplaySettings = {
type: UPDATE_DISPLAY_SETTINGS,
payload: mockApp.displaySettings,
payload: mockApp.displaySettings
};
expect(appReducer(initialState, updateDisplaySettings)).toEqual({
...initialState,
displaySettings: mockApp.displaySettings,
displaySettings: mockApp.displaySettings
});
});
it('should handle updateNavigationSettings', () => {
const updateNavigationSettings = {
type: UPDATE_NAVIGATION_SETTINGS,
payload: mockApp.navigationSettings,
payload: mockApp.navigationSettings
};
expect(appReducer(initialState, updateNavigationSettings)).toEqual({
...initialState,
navigationSettings: mockApp.navigationSettings,
navigationSettings: mockApp.navigationSettings
});
});
it('should handle finishFirstVisit ', () => {
const finishFirstVisit = {
type: FINISH_FIRST_VISIT,
type: FINISH_FIRST_VISIT
};
expect(appReducer(initialState, finishFirstVisit)).toEqual({
...initialState,
isFirstVisit: false,
isFirstVisit: false
});
});
it('should handle updateConnectivity', () => {
const updateConnectivity = {
type: UPDATE_CONNECTIVITY,
payload: false,
payload: false
};
expect(appReducer(initialState, updateConnectivity)).toEqual({
...initialState,
isConnected: false,
isConnected: false
});
});
});
41 changes: 38 additions & 3 deletions src/components/Board/Board.actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
CLICK_SYMBOL,
CLICK_OUTPUT,
CHANGE_OUTPUT,
CHANGE_IMPROVED_PHRASE,
CHANGE_LIVE_MODE,
REPLACE_BOARD,
HISTORY_REMOVE_BOARD,
Expand Down Expand Up @@ -55,6 +56,7 @@ import {
import { isAndroid, writeCvaFile } from '../../cordova-util';
import { DEFAULT_BOARDS } from '../../helpers';
import history from './../../history';
import { improvePhraseAbortController } from '../../api/api';

const BOARDS_PAGE_LIMIT = 100;

Expand Down Expand Up @@ -324,9 +326,42 @@ export function clickOutput(outputPhrase) {
}

export function changeOutput(output) {
return {
type: CHANGE_OUTPUT,
output
return async (dispatch, getState) => {
const {
app: {
navigationSettings: { improvePhraseActive }
}
} = getState();
if (improvePhraseActive) dispatch(improvePhrase(output));
dispatch({
type: CHANGE_OUTPUT,
output
});
};
}

export function improvePhrase(output) {
const improvePhrase = async language => {
const MIN_TILES_TO_IMPROVE = 1;
if (output.length <= MIN_TILES_TO_IMPROVE) return '';
const labels = output.map(symbol => symbol.label);
const phrase = labels.join(' '); //this.handlePhraseToShare();
const improvedPhrase = await API.improvePhrase({ phrase, language });
return improvedPhrase.phrase;
};
tomivm marked this conversation as resolved.
Show resolved Hide resolved
return async (dispatch, getState) => {
try {
const language = getState().language.lang;
if (improvePhraseAbortController?.abort)
improvePhraseAbortController.abort();
const improvedPhrase = await improvePhrase(language);
dispatch({
type: CHANGE_IMPROVED_PHRASE,
improvedPhrase
});
} catch (err) {
console.error('error', err);
}
};
}

Expand Down
12 changes: 10 additions & 2 deletions src/components/Board/Board.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import './Board.css';
import BoardTour from './BoardTour/BoardTour';
import ScrollButtons from '../ScrollButtons';
import { NAVIGATION_BUTTONS_STYLE_SIDES } from '../Settings/Navigation/Navigation.constants';
import ImprovePhraseOutput from './ImprovePhraseOutput';

export class Board extends Component {
static propTypes = {
Expand Down Expand Up @@ -315,7 +316,9 @@ export class Board extends Component {
setIsScroll,
isScroll,
totalRows,
changeDefaultBoard
changeDefaultBoard,
improvedPhrase,
speak
} = this.props;

const tiles = this.renderTiles(board.tiles);
Expand Down Expand Up @@ -524,7 +527,12 @@ export class Board extends Component {
/>
)}
</div>

{navigationSettings.improvePhraseActive && (
<ImprovePhraseOutput
improvedPhrase={improvedPhrase}
speak={speak}
/>
)}
<Dialog
open={this.state.openTitleDialog}
aria-labelledby="board-dialog-title"
Expand Down
1 change: 1 addition & 0 deletions src/components/Board/Board.constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const FOCUS_TILE = 'cboard/Board/FOCUS_TILE';
export const CLICK_SYMBOL = 'cboard/Board/CLICK_SYMBOL';
export const CLICK_OUTPUT = 'cboard/Board/CLICK_OUTPUT';
export const CHANGE_OUTPUT = 'cboard/Board/CHANGE_OUTPUT';
export const CHANGE_IMPROVED_PHRASE = 'cboard/Board/CHANGE_IMPROVED_PHRASE';
export const CHANGE_LIVE_MODE = 'cboard/Board/CHANGE_LIVE_MODE';
export const HISTORY_REMOVE_BOARD = 'cboard/Board/HISTORY_REMOVE_BOARD';
export const UNMARK_BOARD = 'cboard/Board/UNMARK_BOARD';
Expand Down
9 changes: 7 additions & 2 deletions src/components/Board/Board.container.js
Original file line number Diff line number Diff line change
Expand Up @@ -1540,7 +1540,9 @@ export class BoardContainer extends Component {
navHistory,
board,
focusTile,
isPremiumRequiredModalOpen
isPremiumRequiredModalOpen,
improvedPhrase,
speak
} = this.props;

if (!this.state.translatedBoard) {
Expand Down Expand Up @@ -1614,6 +1616,8 @@ export class BoardContainer extends Component {
totalRows={this.state.totalRows}
ref={this.boardRef}
changeDefaultBoard={this.props.changeDefaultBoard}
improvedPhrase={improvedPhrase}
speak={speak}
/>
<Dialog
open={!!this.state.copyPublicBoard && !isPremiumRequiredModalOpen}
Expand Down Expand Up @@ -1726,7 +1730,8 @@ const mapStateToProps = ({
offlineVoiceAlert,
isRootBoardTourEnabled: liveHelp.isRootBoardTourEnabled,
isUnlockedTourEnabled: liveHelp.isUnlockedTourEnabled,
isPremiumRequiredModalOpen: premiumRequiredModalState?.open
isPremiumRequiredModalOpen: premiumRequiredModalState?.open,
improvedPhrase: board.improvedPhrase
};
};

Expand Down
9 changes: 8 additions & 1 deletion src/components/Board/Board.reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
EDIT_TILES,
FOCUS_TILE,
CHANGE_OUTPUT,
CHANGE_IMPROVED_PHRASE,
REPLACE_BOARD,
HISTORY_REMOVE_BOARD,
UNMARK_BOARD,
Expand Down Expand Up @@ -48,7 +49,8 @@ const initialState = {
isFetching: false,
images: [],
isFixed: false,
isLiveMode: false
isLiveMode: false,
improvedPhrase: ''
};

function reconcileBoards(localBoard, remoteBoard) {
Expand Down Expand Up @@ -411,6 +413,11 @@ function boardReducer(state = initialState, action) {
return {
...state
};
case CHANGE_IMPROVED_PHRASE:
return {
...state,
improvedPhrase: action.improvedPhrase
};
default:
return state;
}
Expand Down
41 changes: 41 additions & 0 deletions src/components/Board/ImprovePhraseOutput/ImprovePhraseOutput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react';
import PropTypes from 'prop-types';

import styles from './ImprovePhraseOutput.module.css';

import { Typography } from '@material-ui/core';
import { PlayArrow } from '@material-ui/icons';

const propTypes = {
improvedPhrase: PropTypes.string,
speak: PropTypes.func
};

function ImprovePhraseOutput({ improvedPhrase, speak }) {
const handlePlay = async () => {
if (!improvedPhrase || improvedPhrase.length === 0) return;
speak(improvedPhrase);
};
const enabledControllsClassname = improvedPhrase
? `${styles.text_and_controls} ${styles.enabled}`
: styles.text_and_controls;

return (
<div
tabIndex="0"
className={enabledControllsClassname}
onClick={handlePlay}
>
<Typography className={styles.text} variant="h5">
{improvedPhrase}
</Typography>
{improvedPhrase && (
<PlayArrow className={styles.playArrow} fontSize="large" />
)}
</div>
);
}

ImprovePhraseOutput.propTypes = propTypes;

export default ImprovePhraseOutput;
Loading