From e98e990e00513b1dd32d381d40b66264070b8001 Mon Sep 17 00:00:00 2001 From: = <=> Date: Mon, 31 Aug 2020 13:53:50 +0300 Subject: [PATCH 01/13] set up reducer, selector & action for storing rating object with id key as date + update work on adding rating icon under daystrip --- src/Types/ModalState.ts | 1 + src/actions/modal/modal-actions.ts | 6 +++ src/components/Buttons/RatingButton.tsx | 11 ++++- src/components/DayStrip.tsx | 49 ++++++++++++++++------- src/components/sleepClock/NightRating.tsx | 37 +++++++++-------- src/components/sleepclock.tsx | 17 +++++++- src/store/Reducers/modal/modal-reducer.ts | 6 ++- src/store/Selectors/ModalSelectors.ts | 5 +++ src/store/index.ts | 6 ++- 9 files changed, 102 insertions(+), 36 deletions(-) diff --git a/src/Types/ModalState.ts b/src/Types/ModalState.ts index 43e0b0f..ee8dc04 100644 --- a/src/Types/ModalState.ts +++ b/src/Types/ModalState.ts @@ -4,4 +4,5 @@ export interface ModalState { newHabitModal: boolean editHabitModal: boolean explanationsModal: boolean + ratingDate?: string } diff --git a/src/actions/modal/modal-actions.ts b/src/actions/modal/modal-actions.ts index 40d9107..c0f20b4 100644 --- a/src/actions/modal/modal-actions.ts +++ b/src/actions/modal/modal-actions.ts @@ -2,6 +2,7 @@ export const TOGGLE_NEW_HABIT_MODAL = 'TOGGLE_NEW_HABIT_MODAL' export const TOGGLE_EDIT_HABIT_MODAL = 'TOGGLE_EDIT_HABIT_MODAL' export const TOGGLE_RATING_MODAL = 'TOGGLE_RATING_MODAL' export const TOGGLE_EXPLANATIONS_MODAL = 'TOGGLE_EXPLANATIONS_MODAL' +export const UPDATE_RATING_DATE = 'UPDATE_RATING_DATE' export const toggleNewHabitModal = (value?: boolean) => { return { type: TOGGLE_NEW_HABIT_MODAL, payload: value } @@ -19,3 +20,8 @@ export const toggleExplanationsModal = (value?: boolean) => ({ type: TOGGLE_EXPLANATIONS_MODAL, payload: value }) + +export const updateRatingDate = (ratingDate: string) => ({ + type: UPDATE_RATING_DATE, + payload: ratingDate +}) diff --git a/src/components/Buttons/RatingButton.tsx b/src/components/Buttons/RatingButton.tsx index 249036a..c31692e 100644 --- a/src/components/Buttons/RatingButton.tsx +++ b/src/components/Buttons/RatingButton.tsx @@ -1,11 +1,14 @@ import React, { FC } from 'react' -import { useDispatch } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import styled from 'styled-components/native' import { rateDay } from '../../actions/sleep/sleep-data-actions' import { fonts } from '../../styles/themes' import IconBold from '../iconBold' import TranslatedText from '../TranslatedText' import ScalingButton from './ScalingButton' +import { updateNightQuality } from 'actions/sleep/night-quality-actions' +import { NightQuality } from 'Types/Sleep/NightQuality' +import { getRatingDate } from 'store/Selectors/ModalSelectors' type Props = { selected: boolean @@ -17,9 +20,15 @@ type Props = { const RatingButton: FC = ({ selected, value, title, icon, color }) => { const dispatch = useDispatch() + const ratingDate = useSelector(getRatingDate) const handlePress = () => { dispatch(rateDay(value)) + const nightQuality: NightQuality = { + id: ratingDate, + quality: value + } + dispatch(updateNightQuality(nightQuality)) } return ( diff --git a/src/components/DayStrip.tsx b/src/components/DayStrip.tsx index b9119b8..3fcd819 100644 --- a/src/components/DayStrip.tsx +++ b/src/components/DayStrip.tsx @@ -12,8 +12,10 @@ import { getWeekSelector } from '../store/Selectors/SleepDataSelectors' import { Day } from '../Types/Sleepdata' +import NightRating from './sleepClock/NightRating' const dayWidth = WIDTH / 7 +const spacerHeight = 7 const cardMargin = 5 const DayStrip = () => { @@ -23,24 +25,30 @@ const DayStrip = () => { const renderItem = ({ item, index }: { item: any; index: number }) => { const isToday = moment(item.date).isSame(new Date(), 'day') - const handleOnPress = () => { dispatch(setActiveIndex(index)) } return ( - - - {Moment(item.date).format('ddd')} - - - {Moment(item.date).format('DD')} - - + + + + {Moment(item.date).format('ddd')} + + + {Moment(item.date).format('DD')} + + + + + + + + ) } @@ -78,10 +86,13 @@ const DayStrip = () => { export default memo(DayStrip) +const Container = styled.View` + flex-direction: column; +` + const Segments = styled(SectionList)` - width: ${WIDTH}px; - height: ${dayWidth}px; margin: 20px 0px; + padding: 10px 0px; ` interface SegmentProps extends StyleProps { @@ -124,3 +135,11 @@ const DateNumber = styled.Text` ? props.theme.PRIMARY_BACKGROUND_COLOR : props.theme.SECONDARY_TEXT_COLOR}; ` + +const Spacer = styled.View` + height: ${spacerHeight}px; +` +const NightRatingHolder = styled.View` + justify-content: center; + align-items: center; +` diff --git a/src/components/sleepClock/NightRating.tsx b/src/components/sleepClock/NightRating.tsx index 2b36184..3c8718d 100644 --- a/src/components/sleepClock/NightRating.tsx +++ b/src/components/sleepClock/NightRating.tsx @@ -1,7 +1,10 @@ import React, { FC, memo } from 'react' import { useDispatch } from 'react-redux' import styled from 'styled-components/native' -import { toggleRatingModal } from '../../actions/modal/modal-actions' +import { + toggleRatingModal, + updateRatingDate +} from '../../actions/modal/modal-actions' import getRating from '../../helpers/rating' import { Day } from '../../Types/Sleepdata' import ScalingButton from '../Buttons/ScalingButton' @@ -9,21 +12,32 @@ import { IconBold } from '../iconRegular' type Props = { day: Day - x: number + height: number + width: number + unClickable?: boolean } -const NightRating: FC = ({ day: { rating = 0 }, x }) => { +const NightRating: FC = ({ + day: { rating = 0, date }, + unClickable, + height, + width +}) => { const { icon, color } = getRating(rating) const dispatch = useDispatch() const openModal = () => { + dispatch(updateRatingDate(date)) dispatch(toggleRatingModal()) } return ( - - + + - + @@ -32,16 +46,7 @@ const NightRating: FC = ({ day: { rating = 0 }, x }) => { export default memo(NightRating) -type ContainerProps = { - readonly x: number -} - -const Container = styled.View` - position: absolute; - top: 90px; - right: ${({ x }) => x - 5}px; - z-index: 20; -` +const Container = styled.View`` interface RatingButtonProps { readonly color?: string } diff --git a/src/components/sleepclock.tsx b/src/components/sleepclock.tsx index 115daa4..f5bb927 100644 --- a/src/components/sleepclock.tsx +++ b/src/components/sleepclock.tsx @@ -51,7 +51,6 @@ const Clock: FC = ({ selectedDay, shouldAnimate }: Props) => { } const hasData = selectedDay.night ? selectedDay.night.length !== 0 : false - const isDarkMode = useSelector(getIsDarkMode) return ( @@ -118,7 +117,9 @@ const Clock: FC = ({ selectedDay, shouldAnimate }: Props) => { /> )} - + + + {editMode && ( ` + justify-content: center; + align-items: center; + position: absolute; + top: 90px; + right: ${({ x }) => x - 5}px; + z-index: 20; +` diff --git a/src/store/Reducers/modal/modal-reducer.ts b/src/store/Reducers/modal/modal-reducer.ts index 89fcee3..7918956 100644 --- a/src/store/Reducers/modal/modal-reducer.ts +++ b/src/store/Reducers/modal/modal-reducer.ts @@ -6,7 +6,8 @@ import { TOGGLE_EDIT_HABIT_MODAL, TOGGLE_NEW_HABIT_MODAL, TOGGLE_RATING_MODAL, - TOGGLE_EXPLANATIONS_MODAL + TOGGLE_EXPLANATIONS_MODAL, + UPDATE_RATING_DATE } from '@actions/modal/modal-actions' export const initialState: ModalState = { @@ -40,6 +41,9 @@ const ModalReducer = ( case TOGGLE_NEW_HABIT_MODAL: return { ...state, newHabitModal: !state.newHabitModal } + case UPDATE_RATING_DATE: + return { ...state, ratingDate: payload } + default: return state } diff --git a/src/store/Selectors/ModalSelectors.ts b/src/store/Selectors/ModalSelectors.ts index 2235e2b..2fff2ee 100644 --- a/src/store/Selectors/ModalSelectors.ts +++ b/src/store/Selectors/ModalSelectors.ts @@ -28,3 +28,8 @@ export const getExplanationsModal = createSelector( getModalState, (modalState: ModalState) => modalState.explanationsModal ) + +export const getRatingDate = createSelector( + getModalState, + (modalState: ModalState) => modalState.ratingDate +) diff --git a/src/store/index.ts b/src/store/index.ts index 2391006..4e4fa57 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -37,6 +37,7 @@ import HealthKitReducer from './Reducers/sleep/health-kit-reducer' import sleepclock from './Reducers/sleepclockReducer' import SubscriptionReducer from './Reducers/subscription/subscription-reducer' import user from './Reducers/user/user-reducer' +import NightQuality from './Reducers/sleep/night-quality-reducer' enableES5() enableMapSet() @@ -92,7 +93,10 @@ const rootReducer = combineReducers({ linking: makePersisted('linking', LinkingReducer, undefined), sleepSources: makePersisted('sleepSources', SleepSourceReducer, undefined), healthKit: makePersisted('healthKit', HealthKitReducer, undefined), - insights: makePersisted('insights', InsightsReducer, undefined) + insights: makePersisted('insights', InsightsReducer, undefined), + nightQuality: makePersisted('nightQuality', NightQuality, undefined, [ + serializeTransform + ]) }) const middleware = applyMiddleware(thunk, batchDispatchMiddleware) From 6fd825e448f28dd90393bcc032cdb45602a286c8 Mon Sep 17 00:00:00 2001 From: = <=> Date: Mon, 31 Aug 2020 14:02:39 +0300 Subject: [PATCH 02/13] small update for missing files --- src/Types/Sleep/NightQuality.ts | 8 ++++++ src/actions/sleep/night-quality-actions.ts | 14 ++++++++++ .../Reducers/sleep/night-quality-reducer.ts | 27 +++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 src/Types/Sleep/NightQuality.ts create mode 100644 src/actions/sleep/night-quality-actions.ts create mode 100644 src/store/Reducers/sleep/night-quality-reducer.ts diff --git a/src/Types/Sleep/NightQuality.ts b/src/Types/Sleep/NightQuality.ts new file mode 100644 index 0000000..f453e7c --- /dev/null +++ b/src/Types/Sleep/NightQuality.ts @@ -0,0 +1,8 @@ +export interface NightQualityGeneral { + records: Map +} + +export interface NightQuality { + id: string | undefined + quality: number // 1 - sad, 2 - nothing new, 3 - smirk, 4 - happy +} diff --git a/src/actions/sleep/night-quality-actions.ts b/src/actions/sleep/night-quality-actions.ts new file mode 100644 index 0000000..b329cdc --- /dev/null +++ b/src/actions/sleep/night-quality-actions.ts @@ -0,0 +1,14 @@ +import { NightQuality } from 'Types/Sleep/NightQuality' + +export const UPDATE_NIGHT_QUALITY = 'UPDATE_NIGHT_QUALITY' +export const DELETE_NIGHT_QUALITY = 'DELETE_NIGHT_QUALITY' + +export const updateNightQuality = (nightQuality: NightQuality) => ({ + type: UPDATE_NIGHT_QUALITY, + payload: nightQuality +}) + +export const deleteNightQuality = (nightQualityId: string) => ({ + type: DELETE_NIGHT_QUALITY, + payload: nightQualityId +}) diff --git a/src/store/Reducers/sleep/night-quality-reducer.ts b/src/store/Reducers/sleep/night-quality-reducer.ts new file mode 100644 index 0000000..9264744 --- /dev/null +++ b/src/store/Reducers/sleep/night-quality-reducer.ts @@ -0,0 +1,27 @@ +import ReduxAction from 'Types/ReduxActions' +import { NightQualityGeneral } from 'Types/Sleep/NightQuality' +import { produce } from 'immer' +import { + UPDATE_NIGHT_QUALITY, + DELETE_NIGHT_QUALITY +} from 'actions/sleep/night-quality-actions' + +const initialState: NightQualityGeneral = { + records: new Map() +} + +const reducer = produce((draft: NightQualityGeneral, action: ReduxAction) => { + const { payload, type } = action + + switch (type) { + case UPDATE_NIGHT_QUALITY: + draft.records.set(payload.id, payload) + break + + case DELETE_NIGHT_QUALITY: + draft.records.delete(payload) + break + } +}, initialState) + +export default reducer From 7037dcb71d0c5712418fc19186214d9f8a5f65da Mon Sep 17 00:00:00 2001 From: = <=> Date: Tue, 1 Sep 2020 16:07:45 +0300 Subject: [PATCH 03/13] Now can create and update night rating to cloud, working on syncing back --- src/API.ts | 281 ++++++++++++++++-- src/Types/Sleep/NightQuality.ts | 5 +- src/Types/State.ts | 2 + src/actions/StartupActions.ts | 4 + src/actions/auth/auth-actions.ts | 2 + src/actions/sleep/night-quality-actions.ts | 151 +++++++++- src/components/Buttons/RatingButton.tsx | 13 +- src/graphql/mutations.ts | 103 +++++-- src/graphql/queries.ts | 101 +++++-- src/graphql/subscriptions.ts | 103 +++++-- .../Reducers/sleep/night-quality-reducer.ts | 20 +- 11 files changed, 683 insertions(+), 102 deletions(-) diff --git a/src/API.ts b/src/API.ts index 10bdd1c..f474649 100644 --- a/src/API.ts +++ b/src/API.ts @@ -299,8 +299,7 @@ export type CreateLikedContentInput = { id?: string | null, name?: string | null, type?: string | null, - slug?: string | null, - cover?: string | null, + slug: string, excerpt?: string | null, }; @@ -309,7 +308,6 @@ export type UpdateLikedContentInput = { name?: string | null, type?: string | null, slug?: string | null, - cover?: string | null, excerpt?: string | null, }; @@ -317,6 +315,24 @@ export type DeleteLikedContentInput = { id?: string | null, }; +export type CreateNightRatingInput = { + id?: string | null, + userId: string, + rating: number, + date: string, +}; + +export type UpdateNightRatingInput = { + id: string, + userId?: string | null, + rating?: number | null, + date?: string | null, +}; + +export type DeleteNightRatingInput = { + id?: string | null, +}; + export type ModelRequestFilterInput = { id?: ModelIDFilterInput | null, requesterName?: ModelStringFilterInput | null, @@ -354,19 +370,38 @@ export type ModelLikedContentFilterInput = { name?: ModelStringFilterInput | null, type?: ModelStringFilterInput | null, slug?: ModelStringFilterInput | null, - cover?: ModelStringFilterInput | null, excerpt?: ModelStringFilterInput | null, and?: Array< ModelLikedContentFilterInput | null > | null, or?: Array< ModelLikedContentFilterInput | null > | null, not?: ModelLikedContentFilterInput | null, }; +export type ModelNightRatingFilterInput = { + id?: ModelIDFilterInput | null, + userId?: ModelIDFilterInput | null, + rating?: ModelIntFilterInput | null, + date?: ModelStringFilterInput | null, + and?: Array< ModelNightRatingFilterInput | null > | null, + or?: Array< ModelNightRatingFilterInput | null > | null, + not?: ModelNightRatingFilterInput | null, +}; + export enum ModelSortDirection { ASC = "ASC", DESC = "DESC", } +export type ModelStringKeyConditionInput = { + eq?: string | null, + le?: string | null, + lt?: string | null, + ge?: string | null, + gt?: string | null, + between?: Array< string | null > | null, + beginsWith?: string | null, +}; + export type UpdateConnectionIDMutationVariables = { input: UpdateUserInput, }; @@ -1036,8 +1071,7 @@ export type CreateLikedContentMutation = { id: string | null, name: string | null, type: string | null, - slug: string | null, - cover: string | null, + slug: string, excerpt: string | null, owner: string | null, } | null, @@ -1053,8 +1087,7 @@ export type UpdateLikedContentMutation = { id: string | null, name: string | null, type: string | null, - slug: string | null, - cover: string | null, + slug: string, excerpt: string | null, owner: string | null, } | null, @@ -1070,13 +1103,84 @@ export type DeleteLikedContentMutation = { id: string | null, name: string | null, type: string | null, - slug: string | null, - cover: string | null, + slug: string, excerpt: string | null, owner: string | null, } | null, }; +export type CreateNightRatingMutationVariables = { + input: CreateNightRatingInput, +}; + +export type CreateNightRatingMutation = { + createNightRating: { + __typename: "NightRating", + id: string, + userId: string, + user: { + __typename: "User", + connectionId: string | null, + id: string, + email: string, + nickname: string | null, + darkMode: boolean | null, + intercomId: string | null, + }, + rating: number, + date: string, + owner: string | null, + } | null, +}; + +export type UpdateNightRatingMutationVariables = { + input: UpdateNightRatingInput, +}; + +export type UpdateNightRatingMutation = { + updateNightRating: { + __typename: "NightRating", + id: string, + userId: string, + user: { + __typename: "User", + connectionId: string | null, + id: string, + email: string, + nickname: string | null, + darkMode: boolean | null, + intercomId: string | null, + }, + rating: number, + date: string, + owner: string | null, + } | null, +}; + +export type DeleteNightRatingMutationVariables = { + input: DeleteNightRatingInput, +}; + +export type DeleteNightRatingMutation = { + deleteNightRating: { + __typename: "NightRating", + id: string, + userId: string, + user: { + __typename: "User", + connectionId: string | null, + id: string, + email: string, + nickname: string | null, + darkMode: boolean | null, + intercomId: string | null, + }, + rating: number, + date: string, + owner: string | null, + } | null, +}; + export type GetSleepDataQueryVariables = { id: string, }; @@ -1391,8 +1495,7 @@ export type GetLikedContentQuery = { id: string | null, name: string | null, type: string | null, - slug: string | null, - cover: string | null, + slug: string, excerpt: string | null, owner: string | null, } | null, @@ -1412,8 +1515,7 @@ export type ListLikedContentsQuery = { id: string | null, name: string | null, type: string | null, - slug: string | null, - cover: string | null, + slug: string, excerpt: string | null, owner: string | null, } | null > | null, @@ -1421,6 +1523,51 @@ export type ListLikedContentsQuery = { } | null, }; +export type GetNightRatingQueryVariables = { + id: string, +}; + +export type GetNightRatingQuery = { + getNightRating: { + __typename: "NightRating", + id: string, + userId: string, + user: { + __typename: "User", + connectionId: string | null, + id: string, + email: string, + nickname: string | null, + darkMode: boolean | null, + intercomId: string | null, + }, + rating: number, + date: string, + owner: string | null, + } | null, +}; + +export type ListNightRatingsQueryVariables = { + filter?: ModelNightRatingFilterInput | null, + limit?: number | null, + nextToken?: string | null, +}; + +export type ListNightRatingsQuery = { + listNightRatings: { + __typename: "ModelNightRatingConnection", + items: Array< { + __typename: "NightRating", + id: string, + userId: string, + rating: number, + date: string, + owner: string | null, + } | null > | null, + nextToken: string | null, + } | null, +}; + export type UserByConnectionIdQueryVariables = { connectionId?: string | null, sortDirection?: ModelSortDirection | null, @@ -1471,6 +1618,31 @@ export type CoachingByUserQuery = { } | null, }; +export type LikedContentBySlugQueryVariables = { + slug?: string | null, + id?: ModelStringKeyConditionInput | null, + sortDirection?: ModelSortDirection | null, + filter?: ModelLikedContentFilterInput | null, + limit?: number | null, + nextToken?: string | null, +}; + +export type LikedContentBySlugQuery = { + likedContentBySlug: { + __typename: "ModelLikedContentConnection", + items: Array< { + __typename: "LikedContent", + id: string | null, + name: string | null, + type: string | null, + slug: string, + excerpt: string | null, + owner: string | null, + } | null > | null, + nextToken: string | null, + } | null, +}; + export type OnCreateSleepDataSubscriptionVariables = { owner: string, }; @@ -1963,8 +2135,7 @@ export type OnCreateLikedContentSubscription = { id: string | null, name: string | null, type: string | null, - slug: string | null, - cover: string | null, + slug: string, excerpt: string | null, owner: string | null, } | null, @@ -1980,8 +2151,7 @@ export type OnUpdateLikedContentSubscription = { id: string | null, name: string | null, type: string | null, - slug: string | null, - cover: string | null, + slug: string, excerpt: string | null, owner: string | null, } | null, @@ -1997,9 +2167,80 @@ export type OnDeleteLikedContentSubscription = { id: string | null, name: string | null, type: string | null, - slug: string | null, - cover: string | null, + slug: string, excerpt: string | null, owner: string | null, } | null, }; + +export type OnCreateNightRatingSubscriptionVariables = { + owner: string, +}; + +export type OnCreateNightRatingSubscription = { + onCreateNightRating: { + __typename: "NightRating", + id: string, + userId: string, + user: { + __typename: "User", + connectionId: string | null, + id: string, + email: string, + nickname: string | null, + darkMode: boolean | null, + intercomId: string | null, + }, + rating: number, + date: string, + owner: string | null, + } | null, +}; + +export type OnUpdateNightRatingSubscriptionVariables = { + owner: string, +}; + +export type OnUpdateNightRatingSubscription = { + onUpdateNightRating: { + __typename: "NightRating", + id: string, + userId: string, + user: { + __typename: "User", + connectionId: string | null, + id: string, + email: string, + nickname: string | null, + darkMode: boolean | null, + intercomId: string | null, + }, + rating: number, + date: string, + owner: string | null, + } | null, +}; + +export type OnDeleteNightRatingSubscriptionVariables = { + owner?: string | null, +}; + +export type OnDeleteNightRatingSubscription = { + onDeleteNightRating: { + __typename: "NightRating", + id: string, + userId: string, + user: { + __typename: "User", + connectionId: string | null, + id: string, + email: string, + nickname: string | null, + darkMode: boolean | null, + intercomId: string | null, + }, + rating: number, + date: string, + owner: string | null, + } | null, +}; diff --git a/src/Types/Sleep/NightQuality.ts b/src/Types/Sleep/NightQuality.ts index f453e7c..05e7bce 100644 --- a/src/Types/Sleep/NightQuality.ts +++ b/src/Types/Sleep/NightQuality.ts @@ -3,6 +3,7 @@ export interface NightQualityGeneral { } export interface NightQuality { - id: string | undefined - quality: number // 1 - sad, 2 - nothing new, 3 - smirk, 4 - happy + id: string + rating: number // 1 - sad, 2 - nothing new, 3 - smirk, 4 - happy + date: string } diff --git a/src/Types/State.ts b/src/Types/State.ts index a4b417a..05cc3dc 100644 --- a/src/Types/State.ts +++ b/src/Types/State.ts @@ -31,6 +31,7 @@ import { TrackingState, TrackingState } from './TrackingState' import { UserState, UserState } from './UserState' import { InsightState } from './State/insight-state' +import { NightQualityGeneral } from './Sleep/NightQuality' export interface State { // User @@ -53,6 +54,7 @@ export interface State { calendar: CalendarState sleepclock: SleepClockState sleepscore: any + nightQuality: NightQualityGeneral // heartRate: any; tracking: TrackingState manualData: ManualDataState diff --git a/src/actions/StartupActions.ts b/src/actions/StartupActions.ts index 7dc94f0..6aadeb4 100644 --- a/src/actions/StartupActions.ts +++ b/src/actions/StartupActions.ts @@ -24,6 +24,7 @@ import { prepareSleepDataFetching } from './sleep/health-kit-actions' import { fetchSleepData, updateCalendar } from './sleep/sleep-data-actions' import { updateSubscriptionStatus } from './subscription/subscription-actions' import { getAllWeeks } from './coaching/content-actions' +import { getNightRatingsFromCloud } from './sleep/night-quality-actions' export const startup = (): Thunk => async ( dispatch: Dispatch, @@ -66,6 +67,9 @@ export const startup = (): Thunk => async ( await dispatch(handleBedtimeApproachNotifications()) await dispatch(handleCoachingUncompletedLessonNotifications()) await dispatch(handleCoachingLessonsInWeekNotifications()) + + // Get Night Ratings from Cloud + await dispatch(getNightRatingsFromCloud()) } export const backgroundAction = (): Thunk => async (dispatch: Dispatch) => { diff --git a/src/actions/auth/auth-actions.ts b/src/actions/auth/auth-actions.ts index e5ca527..cc47f87 100644 --- a/src/actions/auth/auth-actions.ts +++ b/src/actions/auth/auth-actions.ts @@ -14,6 +14,7 @@ import ROUTE from '../../config/routes/Routes' import { actionCreators as notificationActions } from '../../store/Reducers/NotificationReducer' import { NotificationType } from '../../Types/NotificationState' import { updateEmail } from '../user/user-actions' +import { getNightRatingsFromCloud } from 'actions/sleep/night-quality-actions' /* ACTION TYPES */ @@ -163,6 +164,7 @@ export const login = (loginEmail: string, loginPassword: string) => async ( await NavigationService.navigate(ROUTE.SLEEP, {}) } + await dispatch(getNightRatingsFromCloud()) await dispatch(loginSuccess(true, email, username)) } catch (error) { console.warn(error) diff --git a/src/actions/sleep/night-quality-actions.ts b/src/actions/sleep/night-quality-actions.ts index b329cdc..dc94bbb 100644 --- a/src/actions/sleep/night-quality-actions.ts +++ b/src/actions/sleep/night-quality-actions.ts @@ -1,14 +1,155 @@ -import { NightQuality } from 'Types/Sleep/NightQuality' +import { NightQuality, NightQualityGeneral } from 'Types/Sleep/NightQuality' +import { Dispatch } from 'redux' +import { GetState } from 'Types/GetState' +import { API, graphqlOperation } from 'aws-amplify' +import { v4 } from 'uuid' +import { createNightRating, updateNightRating } from 'graphql/mutations' +import { + CreateNightRatingInput, + ModelNightRatingFilterInput, + ListNightRatingsQuery, + UpdateNightRatingInput +} from 'API' +import { dispatch } from 'd3' +import { listNightRatings } from 'graphql/queries' export const UPDATE_NIGHT_QUALITY = 'UPDATE_NIGHT_QUALITY' -export const DELETE_NIGHT_QUALITY = 'DELETE_NIGHT_QUALITY' +export const PUSH_NIGHT_QUALITY = 'PUSH_NIGHT_QUALITY' +export const POP_NIGHT_QUALITY = 'POP_NIGHT_QUALITY' export const updateNightQuality = (nightQuality: NightQuality) => ({ type: UPDATE_NIGHT_QUALITY, payload: nightQuality }) -export const deleteNightQuality = (nightQualityId: string) => ({ - type: DELETE_NIGHT_QUALITY, - payload: nightQualityId +export const pushNightQuality = (nightQuality: NightQuality) => ({ + type: PUSH_NIGHT_QUALITY, + payload: nightQuality +}) + +export const popNightQuality = () => ({ + type: POP_NIGHT_QUALITY }) + +export const getNightRatingsFromCloud = () => async ( + dispatch: Dispatch, + getState: GetState +) => { + const { + user: { loggedIn } + } = getState() + + try { + if (loggedIn) { + const { + user: { username } + } = getState() + + const variables: { + filter: ModelNightRatingFilterInput + limit?: number + nextToken?: string + } = { + filter: { + userId: { + eq: username + } + } + } + const response = (await API.graphql( + graphqlOperation(listNightRatings, variables) + )) as any + + // const cloudNightRatings = response + + console.log('at getNightRatingsFromCloud ', response) + } + } catch (err) { + console.log('getNightRatingsFromCloud', err) + } +} + +export const rateNight = ({ id, rating, date }: NightQuality) => async ( + dispatch: Dispatch, + getState: GetState +) => { + const { + user: { authenticated, username }, + nightQuality + } = getState() + + date = date && date.length > 0 ? date : '' + + const newNightRating: NightQuality = { + id, + rating, + date + } + + try { + // Handle cloud update if user is logged in + if (authenticated) { + // We check to see if the rating for date already exists + // If it exists, we update its data in the cloud + if (checkRecordExists(nightQuality, date)) { + const updateNightRatingInput: UpdateNightRatingInput = { + date, + userId: username as string, + rating, + id: nightQuality.records.get(date)?.id as string + } + + await API.graphql( + graphqlOperation(updateNightRating, { input: updateNightRatingInput }) + ) + + await dispatch(updateNightQuality(newNightRating)) + } + + // If it doesn't exist, we create a new one in the cloud + else { + const createNightRatingInput: CreateNightRatingInput = { + date, + userId: username as string, + rating, + id + } + + await API.graphql( + graphqlOperation(createNightRating, { input: createNightRatingInput }) + ) + + await dispatch(pushNightQuality(newNightRating)) + } + } else { + // If record already exists, we update it + if (checkRecordExists(nightQuality, date)) { + await dispatch(updateNightQuality(newNightRating)) + } + // If not, we handle it as local data + else { + // If the new night rating will break the size, we pop the 1st element (the oldest night rating) so the array always remains 31 elements + if (checkIfWillExceedQuantity(nightQuality)) { + await dispatch(popNightQuality()) + } + + // Push the new one in as the 31st element + await dispatch(pushNightQuality(newNightRating)) + } + } + } catch (err) { + console.log('rateNight', err) + } +} + +const checkRecordExists = ({ records }: NightQualityGeneral, date: string) => { + // const index = records.findIndex((nightQuality) => (nightQuality.id = date)) + + // return index !== -1 + return records.has(date) +} + +const checkIfWillExceedQuantity = ({ records }: NightQualityGeneral) => { + // return records.length === 31 + return records.size === 31 +} diff --git a/src/components/Buttons/RatingButton.tsx b/src/components/Buttons/RatingButton.tsx index c31692e..651d550 100644 --- a/src/components/Buttons/RatingButton.tsx +++ b/src/components/Buttons/RatingButton.tsx @@ -6,9 +6,11 @@ import { fonts } from '../../styles/themes' import IconBold from '../iconBold' import TranslatedText from '../TranslatedText' import ScalingButton from './ScalingButton' -import { updateNightQuality } from 'actions/sleep/night-quality-actions' +import { rateNight } from 'actions/sleep/night-quality-actions' import { NightQuality } from 'Types/Sleep/NightQuality' import { getRatingDate } from 'store/Selectors/ModalSelectors' +import { v4 } from 'uuid' +import moment from 'moment' type Props = { selected: boolean @@ -18,17 +20,18 @@ type Props = { color: string } -const RatingButton: FC = ({ selected, value, title, icon, color }) => { +const RatingButton: FC = ({ value, title, icon, color }) => { const dispatch = useDispatch() const ratingDate = useSelector(getRatingDate) const handlePress = () => { dispatch(rateDay(value)) const nightQuality: NightQuality = { - id: ratingDate, - quality: value + id: v4(), + rating: value, + date: ratingDate && ratingDate.length > 0 ? ratingDate : 'unknown' } - dispatch(updateNightQuality(nightQuality)) + dispatch(rateNight(nightQuality)) } return ( diff --git a/src/graphql/mutations.ts b/src/graphql/mutations.ts index e437bab..27666c3 100644 --- a/src/graphql/mutations.ts +++ b/src/graphql/mutations.ts @@ -1,4 +1,5 @@ // tslint:disable +// eslint-disable // this is an auto generated file. This will be overwritten export const createSleepData = /* GraphQL */ ` @@ -26,7 +27,7 @@ export const createSleepData = /* GraphQL */ ` owner } } -` +`; export const updateSleepData = /* GraphQL */ ` mutation UpdateSleepData($input: UpdateSleepDataInput!) { updateSleepData(input: $input) { @@ -52,7 +53,7 @@ export const updateSleepData = /* GraphQL */ ` owner } } -` +`; export const deleteSleepData = /* GraphQL */ ` mutation DeleteSleepData($input: DeleteSleepDataInput!) { deleteSleepData(input: $input) { @@ -78,7 +79,7 @@ export const deleteSleepData = /* GraphQL */ ` owner } } -` +`; export const createRequest = /* GraphQL */ ` mutation CreateRequest($input: CreateRequestInput!) { createRequest(input: $input) { @@ -90,7 +91,7 @@ export const createRequest = /* GraphQL */ ` accepted } } -` +`; export const updateRequest = /* GraphQL */ ` mutation UpdateRequest($input: UpdateRequestInput!) { updateRequest(input: $input) { @@ -102,7 +103,7 @@ export const updateRequest = /* GraphQL */ ` accepted } } -` +`; export const deleteRequest = /* GraphQL */ ` mutation DeleteRequest($input: DeleteRequestInput!) { deleteRequest(input: $input) { @@ -114,7 +115,7 @@ export const deleteRequest = /* GraphQL */ ` accepted } } -` +`; export const createUser = /* GraphQL */ ` mutation CreateUser($input: CreateUserInput!) { createUser(input: $input) { @@ -126,7 +127,7 @@ export const createUser = /* GraphQL */ ` intercomId } } -` +`; export const updateUser = /* GraphQL */ ` mutation UpdateUser($input: UpdateUserInput!) { updateUser(input: $input) { @@ -138,7 +139,7 @@ export const updateUser = /* GraphQL */ ` intercomId } } -` +`; export const deleteUser = /* GraphQL */ ` mutation DeleteUser($input: DeleteUserInput!) { deleteUser(input: $input) { @@ -150,7 +151,7 @@ export const deleteUser = /* GraphQL */ ` intercomId } } -` +`; export const createCoachingData = /* GraphQL */ ` mutation CreateCoachingData($input: CreateCoachingDataInput!) { createCoachingData(input: $input) { @@ -178,7 +179,7 @@ export const createCoachingData = /* GraphQL */ ` owner } } -` +`; export const updateCoachingData = /* GraphQL */ ` mutation UpdateCoachingData($input: UpdateCoachingDataInput!) { updateCoachingData(input: $input) { @@ -206,7 +207,7 @@ export const updateCoachingData = /* GraphQL */ ` owner } } -` +`; export const deleteCoachingData = /* GraphQL */ ` mutation DeleteCoachingData($input: DeleteCoachingDataInput!) { deleteCoachingData(input: $input) { @@ -234,7 +235,7 @@ export const deleteCoachingData = /* GraphQL */ ` owner } } -` +`; export const createHabit = /* GraphQL */ ` mutation CreateHabit($input: CreateHabitInput!) { createHabit(input: $input) { @@ -263,7 +264,7 @@ export const createHabit = /* GraphQL */ ` owner } } -` +`; export const updateHabit = /* GraphQL */ ` mutation UpdateHabit($input: UpdateHabitInput!) { updateHabit(input: $input) { @@ -292,7 +293,7 @@ export const updateHabit = /* GraphQL */ ` owner } } -` +`; export const deleteHabit = /* GraphQL */ ` mutation DeleteHabit($input: DeleteHabitInput!) { deleteHabit(input: $input) { @@ -321,7 +322,7 @@ export const deleteHabit = /* GraphQL */ ` owner } } -` +`; export const createNight = /* GraphQL */ ` mutation CreateNight($input: CreateNightInput!) { createNight(input: $input) { @@ -345,7 +346,7 @@ export const createNight = /* GraphQL */ ` owner } } -` +`; export const updateNight = /* GraphQL */ ` mutation UpdateNight($input: UpdateNightInput!) { updateNight(input: $input) { @@ -369,7 +370,7 @@ export const updateNight = /* GraphQL */ ` owner } } -` +`; export const deleteNight = /* GraphQL */ ` mutation DeleteNight($input: DeleteNightInput!) { deleteNight(input: $input) { @@ -393,7 +394,7 @@ export const deleteNight = /* GraphQL */ ` owner } } -` +`; export const createLikedContent = /* GraphQL */ ` mutation CreateLikedContent($input: CreateLikedContentInput!) { createLikedContent(input: $input) { @@ -401,12 +402,11 @@ export const createLikedContent = /* GraphQL */ ` name type slug - cover excerpt owner } } -` +`; export const updateLikedContent = /* GraphQL */ ` mutation UpdateLikedContent($input: UpdateLikedContentInput!) { updateLikedContent(input: $input) { @@ -414,12 +414,11 @@ export const updateLikedContent = /* GraphQL */ ` name type slug - cover excerpt owner } } -` +`; export const deleteLikedContent = /* GraphQL */ ` mutation DeleteLikedContent($input: DeleteLikedContentInput!) { deleteLikedContent(input: $input) { @@ -427,9 +426,65 @@ export const deleteLikedContent = /* GraphQL */ ` name type slug - cover excerpt owner } } -` +`; +export const createNightRating = /* GraphQL */ ` + mutation CreateNightRating($input: CreateNightRatingInput!) { + createNightRating(input: $input) { + id + userId + user { + connectionId + id + email + nickname + darkMode + intercomId + } + rating + date + owner + } + } +`; +export const updateNightRating = /* GraphQL */ ` + mutation UpdateNightRating($input: UpdateNightRatingInput!) { + updateNightRating(input: $input) { + id + userId + user { + connectionId + id + email + nickname + darkMode + intercomId + } + rating + date + owner + } + } +`; +export const deleteNightRating = /* GraphQL */ ` + mutation DeleteNightRating($input: DeleteNightRatingInput!) { + deleteNightRating(input: $input) { + id + userId + user { + connectionId + id + email + nickname + darkMode + intercomId + } + rating + date + owner + } + } +`; diff --git a/src/graphql/queries.ts b/src/graphql/queries.ts index 6119b72..169b68e 100644 --- a/src/graphql/queries.ts +++ b/src/graphql/queries.ts @@ -1,4 +1,5 @@ // tslint:disable +// eslint-disable // this is an auto generated file. This will be overwritten export const getSleepData = /* GraphQL */ ` @@ -26,7 +27,7 @@ export const getSleepData = /* GraphQL */ ` owner } } -` +`; export const listSleepDatas = /* GraphQL */ ` query ListSleepDatas( $filter: ModelSleepDataFilterInput @@ -44,7 +45,7 @@ export const listSleepDatas = /* GraphQL */ ` nextToken } } -` +`; export const getRequest = /* GraphQL */ ` query GetRequest($id: ID!) { getRequest(id: $id) { @@ -56,7 +57,7 @@ export const getRequest = /* GraphQL */ ` accepted } } -` +`; export const listRequests = /* GraphQL */ ` query ListRequests( $filter: ModelRequestFilterInput @@ -75,7 +76,7 @@ export const listRequests = /* GraphQL */ ` nextToken } } -` +`; export const getUser = /* GraphQL */ ` query GetUser($id: ID!) { getUser(id: $id) { @@ -87,7 +88,7 @@ export const getUser = /* GraphQL */ ` intercomId } } -` +`; export const listUsers = /* GraphQL */ ` query ListUsers( $filter: ModelUserFilterInput @@ -106,7 +107,7 @@ export const listUsers = /* GraphQL */ ` nextToken } } -` +`; export const getCoachingData = /* GraphQL */ ` query GetCoachingData($id: ID!) { getCoachingData(id: $id) { @@ -134,7 +135,7 @@ export const getCoachingData = /* GraphQL */ ` owner } } -` +`; export const listCoachingDatas = /* GraphQL */ ` query ListCoachingDatas( $filter: ModelCoachingDataFilterInput @@ -155,7 +156,7 @@ export const listCoachingDatas = /* GraphQL */ ` nextToken } } -` +`; export const getHabit = /* GraphQL */ ` query GetHabit($id: ID!) { getHabit(id: $id) { @@ -184,7 +185,7 @@ export const getHabit = /* GraphQL */ ` owner } } -` +`; export const listHabits = /* GraphQL */ ` query ListHabits( $filter: ModelHabitFilterInput @@ -208,7 +209,7 @@ export const listHabits = /* GraphQL */ ` nextToken } } -` +`; export const getNight = /* GraphQL */ ` query GetNight($id: ID!) { getNight(id: $id) { @@ -232,7 +233,7 @@ export const getNight = /* GraphQL */ ` owner } } -` +`; export const listNights = /* GraphQL */ ` query ListNights( $filter: ModelNightFilterInput @@ -255,7 +256,7 @@ export const listNights = /* GraphQL */ ` nextToken } } -` +`; export const getLikedContent = /* GraphQL */ ` query GetLikedContent($id: ID!) { getLikedContent(id: $id) { @@ -263,12 +264,11 @@ export const getLikedContent = /* GraphQL */ ` name type slug - cover excerpt owner } } -` +`; export const listLikedContents = /* GraphQL */ ` query ListLikedContents( $filter: ModelLikedContentFilterInput @@ -281,14 +281,50 @@ export const listLikedContents = /* GraphQL */ ` name type slug - cover excerpt owner } nextToken } } -` +`; +export const getNightRating = /* GraphQL */ ` + query GetNightRating($id: ID!) { + getNightRating(id: $id) { + id + userId + user { + connectionId + id + email + nickname + darkMode + intercomId + } + rating + date + owner + } + } +`; +export const listNightRatings = /* GraphQL */ ` + query ListNightRatings( + $filter: ModelNightRatingFilterInput + $limit: Int + $nextToken: String + ) { + listNightRatings(filter: $filter, limit: $limit, nextToken: $nextToken) { + items { + id + userId + rating + date + owner + } + nextToken + } + } +`; export const userByConnectionId = /* GraphQL */ ` query UserByConnectionId( $connectionId: String @@ -315,7 +351,7 @@ export const userByConnectionId = /* GraphQL */ ` nextToken } } -` +`; export const coachingByUser = /* GraphQL */ ` query CoachingByUser( $userId: ID @@ -344,4 +380,33 @@ export const coachingByUser = /* GraphQL */ ` nextToken } } -` +`; +export const likedContentBySlug = /* GraphQL */ ` + query LikedContentBySlug( + $slug: String + $id: ModelStringKeyConditionInput + $sortDirection: ModelSortDirection + $filter: ModelLikedContentFilterInput + $limit: Int + $nextToken: String + ) { + likedContentBySlug( + slug: $slug + id: $id + sortDirection: $sortDirection + filter: $filter + limit: $limit + nextToken: $nextToken + ) { + items { + id + name + type + slug + excerpt + owner + } + nextToken + } + } +`; diff --git a/src/graphql/subscriptions.ts b/src/graphql/subscriptions.ts index 2d5203c..b5f2a71 100644 --- a/src/graphql/subscriptions.ts +++ b/src/graphql/subscriptions.ts @@ -1,4 +1,5 @@ // tslint:disable +// eslint-disable // this is an auto generated file. This will be overwritten export const onCreateSleepData = /* GraphQL */ ` @@ -26,7 +27,7 @@ export const onCreateSleepData = /* GraphQL */ ` owner } } -` +`; export const onUpdateSleepData = /* GraphQL */ ` subscription OnUpdateSleepData($owner: String!) { onUpdateSleepData(owner: $owner) { @@ -52,7 +53,7 @@ export const onUpdateSleepData = /* GraphQL */ ` owner } } -` +`; export const onDeleteSleepData = /* GraphQL */ ` subscription OnDeleteSleepData($owner: String) { onDeleteSleepData(owner: $owner) { @@ -78,7 +79,7 @@ export const onDeleteSleepData = /* GraphQL */ ` owner } } -` +`; export const onCreateRequest = /* GraphQL */ ` subscription OnCreateRequest($owner: String!) { onCreateRequest(owner: $owner) { @@ -90,7 +91,7 @@ export const onCreateRequest = /* GraphQL */ ` accepted } } -` +`; export const onUpdateRequest = /* GraphQL */ ` subscription OnUpdateRequest($userId: String!) { onUpdateRequest(userId: $userId) { @@ -102,7 +103,7 @@ export const onUpdateRequest = /* GraphQL */ ` accepted } } -` +`; export const onDeleteRequest = /* GraphQL */ ` subscription OnDeleteRequest($userId: String) { onDeleteRequest(userId: $userId) { @@ -114,7 +115,7 @@ export const onDeleteRequest = /* GraphQL */ ` accepted } } -` +`; export const onCreateUser = /* GraphQL */ ` subscription OnCreateUser { onCreateUser { @@ -126,7 +127,7 @@ export const onCreateUser = /* GraphQL */ ` intercomId } } -` +`; export const onUpdateUser = /* GraphQL */ ` subscription OnUpdateUser($owner: String!) { onUpdateUser(owner: $owner) { @@ -138,7 +139,7 @@ export const onUpdateUser = /* GraphQL */ ` intercomId } } -` +`; export const onDeleteUser = /* GraphQL */ ` subscription OnDeleteUser($owner: String) { onDeleteUser(owner: $owner) { @@ -150,7 +151,7 @@ export const onDeleteUser = /* GraphQL */ ` intercomId } } -` +`; export const onCreateCoachingData = /* GraphQL */ ` subscription OnCreateCoachingData($owner: String!) { onCreateCoachingData(owner: $owner) { @@ -178,7 +179,7 @@ export const onCreateCoachingData = /* GraphQL */ ` owner } } -` +`; export const onUpdateCoachingData = /* GraphQL */ ` subscription OnUpdateCoachingData($owner: String!) { onUpdateCoachingData(owner: $owner) { @@ -206,7 +207,7 @@ export const onUpdateCoachingData = /* GraphQL */ ` owner } } -` +`; export const onDeleteCoachingData = /* GraphQL */ ` subscription OnDeleteCoachingData($owner: String) { onDeleteCoachingData(owner: $owner) { @@ -234,7 +235,7 @@ export const onDeleteCoachingData = /* GraphQL */ ` owner } } -` +`; export const onCreateHabit = /* GraphQL */ ` subscription OnCreateHabit($owner: String!) { onCreateHabit(owner: $owner) { @@ -263,7 +264,7 @@ export const onCreateHabit = /* GraphQL */ ` owner } } -` +`; export const onUpdateHabit = /* GraphQL */ ` subscription OnUpdateHabit($owner: String!) { onUpdateHabit(owner: $owner) { @@ -292,7 +293,7 @@ export const onUpdateHabit = /* GraphQL */ ` owner } } -` +`; export const onDeleteHabit = /* GraphQL */ ` subscription OnDeleteHabit($owner: String) { onDeleteHabit(owner: $owner) { @@ -321,7 +322,7 @@ export const onDeleteHabit = /* GraphQL */ ` owner } } -` +`; export const onCreateNight = /* GraphQL */ ` subscription OnCreateNight($owner: String!) { onCreateNight(owner: $owner) { @@ -345,7 +346,7 @@ export const onCreateNight = /* GraphQL */ ` owner } } -` +`; export const onUpdateNight = /* GraphQL */ ` subscription OnUpdateNight($owner: String!) { onUpdateNight(owner: $owner) { @@ -369,7 +370,7 @@ export const onUpdateNight = /* GraphQL */ ` owner } } -` +`; export const onDeleteNight = /* GraphQL */ ` subscription OnDeleteNight($owner: String) { onDeleteNight(owner: $owner) { @@ -393,7 +394,7 @@ export const onDeleteNight = /* GraphQL */ ` owner } } -` +`; export const onCreateLikedContent = /* GraphQL */ ` subscription OnCreateLikedContent($owner: String) { onCreateLikedContent(owner: $owner) { @@ -401,12 +402,11 @@ export const onCreateLikedContent = /* GraphQL */ ` name type slug - cover excerpt owner } } -` +`; export const onUpdateLikedContent = /* GraphQL */ ` subscription OnUpdateLikedContent($owner: String) { onUpdateLikedContent(owner: $owner) { @@ -414,12 +414,11 @@ export const onUpdateLikedContent = /* GraphQL */ ` name type slug - cover excerpt owner } } -` +`; export const onDeleteLikedContent = /* GraphQL */ ` subscription OnDeleteLikedContent($owner: String) { onDeleteLikedContent(owner: $owner) { @@ -427,9 +426,65 @@ export const onDeleteLikedContent = /* GraphQL */ ` name type slug - cover excerpt owner } } -` +`; +export const onCreateNightRating = /* GraphQL */ ` + subscription OnCreateNightRating($owner: String!) { + onCreateNightRating(owner: $owner) { + id + userId + user { + connectionId + id + email + nickname + darkMode + intercomId + } + rating + date + owner + } + } +`; +export const onUpdateNightRating = /* GraphQL */ ` + subscription OnUpdateNightRating($owner: String!) { + onUpdateNightRating(owner: $owner) { + id + userId + user { + connectionId + id + email + nickname + darkMode + intercomId + } + rating + date + owner + } + } +`; +export const onDeleteNightRating = /* GraphQL */ ` + subscription OnDeleteNightRating($owner: String) { + onDeleteNightRating(owner: $owner) { + id + userId + user { + connectionId + id + email + nickname + darkMode + intercomId + } + rating + date + owner + } + } +`; diff --git a/src/store/Reducers/sleep/night-quality-reducer.ts b/src/store/Reducers/sleep/night-quality-reducer.ts index 9264744..1187292 100644 --- a/src/store/Reducers/sleep/night-quality-reducer.ts +++ b/src/store/Reducers/sleep/night-quality-reducer.ts @@ -3,7 +3,8 @@ import { NightQualityGeneral } from 'Types/Sleep/NightQuality' import { produce } from 'immer' import { UPDATE_NIGHT_QUALITY, - DELETE_NIGHT_QUALITY + PUSH_NIGHT_QUALITY, + POP_NIGHT_QUALITY } from 'actions/sleep/night-quality-actions' const initialState: NightQualityGeneral = { @@ -15,11 +16,22 @@ const reducer = produce((draft: NightQualityGeneral, action: ReduxAction) => { switch (type) { case UPDATE_NIGHT_QUALITY: - draft.records.set(payload.id, payload) + // const index = draft.records.findIndex( + // (nightQuality) => nightQuality.date === payload.date + // ) + // draft.records[index] = payload + draft.records.set(payload.date, payload) break - case DELETE_NIGHT_QUALITY: - draft.records.delete(payload) + case PUSH_NIGHT_QUALITY: + // draft.records.push(payload) + draft.records.set(payload.date, payload) + break + + case POP_NIGHT_QUALITY: + // draft.records.slice(1, draft.records.length) + const poppedMap = Array.from(draft.records).slice(1, draft.records.size) + draft.records = new Map(poppedMap) break } }, initialState) From 4286605055803d7c8afa65a3b5cdf7a937af42b4 Mon Sep 17 00:00:00 2001 From: = <=> Date: Tue, 1 Sep 2020 18:34:02 +0300 Subject: [PATCH 04/13] Can now fetch, update, create night ratings from/to cloud, need to write tests & work on displaying ratings in charts --- src/Types/Sleep/NightQuality.ts | 3 +- src/Types/State.ts | 4 +- src/actions/StartupActions.ts | 6 +- src/actions/auth/auth-actions.ts | 2 +- src/actions/sleep/night-quality-actions.ts | 102 ++++++++++++------ src/components/sleepClock/NightRating.tsx | 21 ++-- .../Reducers/sleep/night-quality-reducer.ts | 41 ++++--- .../night-quality-selector.ts | 26 +++++ 8 files changed, 143 insertions(+), 62 deletions(-) create mode 100644 src/store/Selectors/night-quality-selectors/night-quality-selector.ts diff --git a/src/Types/Sleep/NightQuality.ts b/src/Types/Sleep/NightQuality.ts index 05e7bce..25c1ca2 100644 --- a/src/Types/Sleep/NightQuality.ts +++ b/src/Types/Sleep/NightQuality.ts @@ -1,5 +1,6 @@ -export interface NightQualityGeneral { +export interface NightQualityState { records: Map + localRecords: Map } export interface NightQuality { diff --git a/src/Types/State.ts b/src/Types/State.ts index 05cc3dc..38e95b3 100644 --- a/src/Types/State.ts +++ b/src/Types/State.ts @@ -31,7 +31,7 @@ import { TrackingState, TrackingState } from './TrackingState' import { UserState, UserState } from './UserState' import { InsightState } from './State/insight-state' -import { NightQualityGeneral } from './Sleep/NightQuality' +import { NightQualityState } from './Sleep/NightQuality' export interface State { // User @@ -54,7 +54,7 @@ export interface State { calendar: CalendarState sleepclock: SleepClockState sleepscore: any - nightQuality: NightQualityGeneral + nightQuality: NightQualityState // heartRate: any; tracking: TrackingState manualData: ManualDataState diff --git a/src/actions/StartupActions.ts b/src/actions/StartupActions.ts index 6aadeb4..551df6e 100644 --- a/src/actions/StartupActions.ts +++ b/src/actions/StartupActions.ts @@ -61,15 +61,15 @@ export const startup = (): Thunk => async ( if (isAuthenticated) { await dispatch(updateCoachingInCloud()) + + // Get Night Ratings from Cloud + await dispatch(getNightRatingsFromCloud()) } await dispatch(calculateInsights()) await dispatch(handleBedtimeApproachNotifications()) await dispatch(handleCoachingUncompletedLessonNotifications()) await dispatch(handleCoachingLessonsInWeekNotifications()) - - // Get Night Ratings from Cloud - await dispatch(getNightRatingsFromCloud()) } export const backgroundAction = (): Thunk => async (dispatch: Dispatch) => { diff --git a/src/actions/auth/auth-actions.ts b/src/actions/auth/auth-actions.ts index cc47f87..b05c76f 100644 --- a/src/actions/auth/auth-actions.ts +++ b/src/actions/auth/auth-actions.ts @@ -164,7 +164,7 @@ export const login = (loginEmail: string, loginPassword: string) => async ( await NavigationService.navigate(ROUTE.SLEEP, {}) } - await dispatch(getNightRatingsFromCloud()) + await dispatch(getNightRatingsFromCloud(username)) await dispatch(loginSuccess(true, email, username)) } catch (error) { console.warn(error) diff --git a/src/actions/sleep/night-quality-actions.ts b/src/actions/sleep/night-quality-actions.ts index dc94bbb..2edfc15 100644 --- a/src/actions/sleep/night-quality-actions.ts +++ b/src/actions/sleep/night-quality-actions.ts @@ -1,4 +1,4 @@ -import { NightQuality, NightQualityGeneral } from 'Types/Sleep/NightQuality' +import { NightQuality, NightQualityState } from 'Types/Sleep/NightQuality' import { Dispatch } from 'redux' import { GetState } from 'Types/GetState' import { API, graphqlOperation } from 'aws-amplify' @@ -12,10 +12,14 @@ import { } from 'API' import { dispatch } from 'd3' import { listNightRatings } from 'graphql/queries' +import RatingModal from 'components/RatingModal' export const UPDATE_NIGHT_QUALITY = 'UPDATE_NIGHT_QUALITY' export const PUSH_NIGHT_QUALITY = 'PUSH_NIGHT_QUALITY' -export const POP_NIGHT_QUALITY = 'POP_NIGHT_QUALITY' +export const LOAD_NIGHT_QUALITY_FROM_CLOUD = 'LOAD_NIGHT_QUALITY_FROM_CLOUD' +export const UPDATE_NIGHT_QUALITY_LOCAL = 'UPDATE_NIGHT_QUALITY_LOCAL' +export const PUSH_NIGHT_QUALITY_LOCAL = 'PUSH_NIGHT_QUALITY_LOCAL' +export const POP_NIGHT_QUALITY_LOCAL = 'POP_NIGHT_QUALITY_LOCAL' export const updateNightQuality = (nightQuality: NightQuality) => ({ type: UPDATE_NIGHT_QUALITY, @@ -27,48 +31,82 @@ export const pushNightQuality = (nightQuality: NightQuality) => ({ payload: nightQuality }) -export const popNightQuality = () => ({ - type: POP_NIGHT_QUALITY +export const updateNightQualityLocally = (nightQuality: NightQuality) => ({ + type: UPDATE_NIGHT_QUALITY_LOCAL, + payload: nightQuality +}) + +export const pushNightQualityLocally = (nightQuality: NightQuality) => ({ + type: PUSH_NIGHT_QUALITY_LOCAL, + payload: nightQuality +}) + +export const popNightQualityLocally = () => ({ + type: POP_NIGHT_QUALITY_LOCAL }) -export const getNightRatingsFromCloud = () => async ( +export const loadNightQualityFromCloud = ( + nightQualityFromCloud: Map +) => ({ + type: LOAD_NIGHT_QUALITY_FROM_CLOUD, + payload: nightQualityFromCloud +}) + +export const getNightRatingsFromCloud = (username?: string) => async ( dispatch: Dispatch, getState: GetState ) => { - const { - user: { loggedIn } - } = getState() - try { - if (loggedIn) { + if (!username) { const { - user: { username } + user: { authenticated } } = getState() - const variables: { - filter: ModelNightRatingFilterInput - limit?: number - nextToken?: string - } = { - filter: { - userId: { - eq: username - } + if (authenticated) + username = getState().user.username as string | undefined + else username = 'unknown' + } + + const variables: { + filter: ModelNightRatingFilterInput + limit?: number + nextToken?: string + } = { + filter: { + userId: { + eq: username } } - const response = (await API.graphql( - graphqlOperation(listNightRatings, variables) - )) as any - - // const cloudNightRatings = response - - console.log('at getNightRatingsFromCloud ', response) } + const response = (await API.graphql( + graphqlOperation(listNightRatings, variables) + )) as any + + const cloudNightRatings: Array = + response.data.listNightRatings.items + + await dispatch( + loadNightQualityFromCloud( + convertNightQualityFromCloudToMap(cloudNightRatings) + ) + ) } catch (err) { console.log('getNightRatingsFromCloud', err) } } +const convertNightQualityFromCloudToMap = ( + cloudNightRatings: Array +) => { + const map = new Map() + + cloudNightRatings.forEach((rating) => { + map.set(rating.date, rating) + }) + + return map +} + export const rateNight = ({ id, rating, date }: NightQuality) => async ( dispatch: Dispatch, getState: GetState @@ -124,17 +162,17 @@ export const rateNight = ({ id, rating, date }: NightQuality) => async ( } else { // If record already exists, we update it if (checkRecordExists(nightQuality, date)) { - await dispatch(updateNightQuality(newNightRating)) + await dispatch(updateNightQualityLocally(newNightRating)) } // If not, we handle it as local data else { // If the new night rating will break the size, we pop the 1st element (the oldest night rating) so the array always remains 31 elements if (checkIfWillExceedQuantity(nightQuality)) { - await dispatch(popNightQuality()) + await dispatch(popNightQualityLocally()) } // Push the new one in as the 31st element - await dispatch(pushNightQuality(newNightRating)) + await dispatch(pushNightQualityLocally(newNightRating)) } } } catch (err) { @@ -142,14 +180,14 @@ export const rateNight = ({ id, rating, date }: NightQuality) => async ( } } -const checkRecordExists = ({ records }: NightQualityGeneral, date: string) => { +const checkRecordExists = ({ records }: NightQualityState, date: string) => { // const index = records.findIndex((nightQuality) => (nightQuality.id = date)) // return index !== -1 return records.has(date) } -const checkIfWillExceedQuantity = ({ records }: NightQualityGeneral) => { +const checkIfWillExceedQuantity = ({ records }: NightQualityState) => { // return records.length === 31 return records.size === 31 } diff --git a/src/components/sleepClock/NightRating.tsx b/src/components/sleepClock/NightRating.tsx index 3c8718d..0fd9946 100644 --- a/src/components/sleepClock/NightRating.tsx +++ b/src/components/sleepClock/NightRating.tsx @@ -1,5 +1,5 @@ -import React, { FC, memo } from 'react' -import { useDispatch } from 'react-redux' +import React, { FC, memo, useMemo } from 'react' +import { useDispatch, useSelector } from 'react-redux' import styled from 'styled-components/native' import { toggleRatingModal, @@ -9,6 +9,8 @@ import getRating from '../../helpers/rating' import { Day } from '../../Types/Sleepdata' import ScalingButton from '../Buttons/ScalingButton' import { IconBold } from '../iconRegular' +import { makeGetRatingOnDate } from 'store/Selectors/night-quality-selectors/night-quality-selector' +import { State } from 'Types/State' type Props = { day: Day @@ -17,13 +19,14 @@ type Props = { unClickable?: boolean } -const NightRating: FC = ({ - day: { rating = 0, date }, - unClickable, - height, - width -}) => { - const { icon, color } = getRating(rating) +const NightRating: FC = ({ day, unClickable, height, width }) => { + const { date } = day + const getRatingOnDate = useMemo(makeGetRatingOnDate, []) + const ratingDate = useSelector((state: State) => + getRatingOnDate(state, { day }) + ) + + const { icon, color } = getRating(ratingDate?.rating) const dispatch = useDispatch() const openModal = () => { diff --git a/src/store/Reducers/sleep/night-quality-reducer.ts b/src/store/Reducers/sleep/night-quality-reducer.ts index 1187292..a0b6411 100644 --- a/src/store/Reducers/sleep/night-quality-reducer.ts +++ b/src/store/Reducers/sleep/night-quality-reducer.ts @@ -1,37 +1,50 @@ import ReduxAction from 'Types/ReduxActions' -import { NightQualityGeneral } from 'Types/Sleep/NightQuality' +import { NightQualityState } from 'Types/Sleep/NightQuality' import { produce } from 'immer' import { UPDATE_NIGHT_QUALITY, PUSH_NIGHT_QUALITY, - POP_NIGHT_QUALITY + LOAD_NIGHT_QUALITY_FROM_CLOUD, + UPDATE_NIGHT_QUALITY_LOCAL, + PUSH_NIGHT_QUALITY_LOCAL, + POP_NIGHT_QUALITY_LOCAL } from 'actions/sleep/night-quality-actions' -const initialState: NightQualityGeneral = { - records: new Map() +const initialState: NightQualityState = { + records: new Map(), + localRecords: new Map() } -const reducer = produce((draft: NightQualityGeneral, action: ReduxAction) => { +const reducer = produce((draft: NightQualityState, action: ReduxAction) => { const { payload, type } = action switch (type) { case UPDATE_NIGHT_QUALITY: - // const index = draft.records.findIndex( - // (nightQuality) => nightQuality.date === payload.date - // ) - // draft.records[index] = payload draft.records.set(payload.date, payload) break case PUSH_NIGHT_QUALITY: - // draft.records.push(payload) draft.records.set(payload.date, payload) break - case POP_NIGHT_QUALITY: - // draft.records.slice(1, draft.records.length) - const poppedMap = Array.from(draft.records).slice(1, draft.records.size) - draft.records = new Map(poppedMap) + case LOAD_NIGHT_QUALITY_FROM_CLOUD: + draft.records = payload + break + + case UPDATE_NIGHT_QUALITY_LOCAL: + draft.localRecords.set(payload.date, payload) + break + + case PUSH_NIGHT_QUALITY_LOCAL: + draft.localRecords.set(payload.date, payload) + break + + case POP_NIGHT_QUALITY_LOCAL: + const poppedMap = Array.from(draft.localRecords).slice( + 1, + draft.localRecords.size + ) + draft.localRecords = new Map(poppedMap) break } }, initialState) diff --git a/src/store/Selectors/night-quality-selectors/night-quality-selector.ts b/src/store/Selectors/night-quality-selectors/night-quality-selector.ts new file mode 100644 index 0000000..2d1c572 --- /dev/null +++ b/src/store/Selectors/night-quality-selectors/night-quality-selector.ts @@ -0,0 +1,26 @@ +import { createSelector } from 'reselect' +import { State } from 'Types/State' +import { NightQualityState } from 'Types/Sleep/NightQuality' +import { UserState } from 'Types/UserState' +import { Day } from 'Types/Sleepdata' + +const getNightQualityState = (state: State) => state.nightQuality +const getUserState = (state: State) => state.user +const getProps = (state: State, props: { day: Day }) => props.day.date + +export const makeGetRatingOnDate = () => + createSelector( + getNightQualityState, + getUserState, + getProps, + ( + nightQualityState: NightQualityState, + userState: UserState, + date: string + ) => { + const { authenticated } = userState + if (authenticated) return nightQualityState.records.get(date) + + return nightQualityState.localRecords.get(date) + } + ) From bfaaee49075671aa151132aa62bb622a7f07e91a Mon Sep 17 00:00:00 2001 From: = <=> Date: Wed, 2 Sep 2020 18:43:16 +0300 Subject: [PATCH 05/13] Update work on adding rating icons to sleep chart, need to write tests --- .../Charts/SleepTimeChart/XTicks.tsx | 41 ++++++++++++++++--- src/components/Charts/sleepTimeChart.tsx | 4 +- src/components/DayStrip.tsx | 7 +++- src/components/sleepClock/NightRating.tsx | 8 ++-- src/components/sleepclock.tsx | 2 +- .../night-quality-selector.ts | 3 +- 6 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/components/Charts/SleepTimeChart/XTicks.tsx b/src/components/Charts/SleepTimeChart/XTicks.tsx index 742d378..4f2eb1c 100644 --- a/src/components/Charts/SleepTimeChart/XTicks.tsx +++ b/src/components/Charts/SleepTimeChart/XTicks.tsx @@ -1,11 +1,13 @@ import { ScaleTime } from 'd3' import moment from 'moment' import React, { memo } from 'react' +import { View } from 'react-native' import { G, Text } from 'react-native-svg' import { useSelector } from 'react-redux' import styled from 'styled-components/native' import { getTextColorOnTheme } from '../../../store/Selectors/UserSelectors' import { fonts } from '../../../styles/themes' +import NightRating from 'components/sleepClock/NightRating' type Props = { scaleX: ScaleTime @@ -16,26 +18,35 @@ type Props = { const XTicks = ({ scaleX, chartHeight, barWidth, ticks }: Props) => { const color = useSelector(getTextColorOnTheme) + const tickElements = ticks.map((tick, index) => { + const date = moment(tick).toISOString() const x = scaleX(tick) + barWidth / 2 return ( - + y={chartHeight - 35}> {moment(tick).format('ddd')} - + + y={chartHeight - 50}> {moment(tick).format('DD')} + + + + ) }) @@ -43,7 +54,7 @@ const XTicks = ({ scaleX, chartHeight, barWidth, ticks }: Props) => { return {tickElements} } -const Day = styled(Text).attrs(({ theme }) => ({ +const DayText = styled(Text).attrs(({ theme }) => ({ fill: theme.PRIMARY_TEXT_COLOR }))`` @@ -51,4 +62,24 @@ const LongDate = styled(Text).attrs(({ theme }) => ({ fill: theme.PRIMARY_TEXT_COLOR }))`` +interface RatingIconContainerProps { + x: number + y: number + children: React.ReactNode + barWidth: number +} + +const RatingIconContainer = (props: RatingIconContainerProps) => ( + + {props.children} + +) + export default memo(XTicks) diff --git a/src/components/Charts/sleepTimeChart.tsx b/src/components/Charts/sleepTimeChart.tsx index 8385f35..934d3e0 100644 --- a/src/components/Charts/sleepTimeChart.tsx +++ b/src/components/Charts/sleepTimeChart.tsx @@ -1,7 +1,7 @@ import * as d3 from 'd3' import moment from 'moment' import React, { memo, useMemo, useState } from 'react' -import { Dimensions, View } from 'react-native' +import { Dimensions, View, Text } from 'react-native' import { ScrollView } from 'react-native-gesture-handler' import Svg from 'react-native-svg' import { useSelector } from 'react-redux' @@ -58,7 +58,7 @@ const SleepTimeChart = () => { ) ] - const scaleX = d3.scaleTime().domain(xDomain).range([paddingLeft, chartWidth]) + const scaleX = d3.scaleTime().domain(xDomain).range([paddingLeft, chartWidth - paddingRight]) const scaleY = d3 .scaleTime() diff --git a/src/components/DayStrip.tsx b/src/components/DayStrip.tsx index 3fcd819..067c47a 100644 --- a/src/components/DayStrip.tsx +++ b/src/components/DayStrip.tsx @@ -46,7 +46,12 @@ const DayStrip = () => { - + ) diff --git a/src/components/sleepClock/NightRating.tsx b/src/components/sleepClock/NightRating.tsx index 0fd9946..97ca91a 100644 --- a/src/components/sleepClock/NightRating.tsx +++ b/src/components/sleepClock/NightRating.tsx @@ -6,24 +6,22 @@ import { updateRatingDate } from '../../actions/modal/modal-actions' import getRating from '../../helpers/rating' -import { Day } from '../../Types/Sleepdata' import ScalingButton from '../Buttons/ScalingButton' import { IconBold } from '../iconRegular' import { makeGetRatingOnDate } from 'store/Selectors/night-quality-selectors/night-quality-selector' import { State } from 'Types/State' type Props = { - day: Day + date: string height: number width: number unClickable?: boolean } -const NightRating: FC = ({ day, unClickable, height, width }) => { - const { date } = day +const NightRating: FC = ({ date, unClickable, height, width }) => { const getRatingOnDate = useMemo(makeGetRatingOnDate, []) const ratingDate = useSelector((state: State) => - getRatingOnDate(state, { day }) + getRatingOnDate(state, { date }) ) const { icon, color } = getRating(ratingDate?.rating) diff --git a/src/components/sleepclock.tsx b/src/components/sleepclock.tsx index f5bb927..542e794 100644 --- a/src/components/sleepclock.tsx +++ b/src/components/sleepclock.tsx @@ -118,7 +118,7 @@ const Clock: FC = ({ selectedDay, shouldAnimate }: Props) => { )} - + {editMode && ( state.nightQuality const getUserState = (state: State) => state.user -const getProps = (state: State, props: { day: Day }) => props.day.date +const getProps = (state: State, { date }: { date: string }) => date export const makeGetRatingOnDate = () => createSelector( From bda8a2418f84d98b15e7dfd376ad958390c236d6 Mon Sep 17 00:00:00 2001 From: = <=> Date: Wed, 2 Sep 2020 21:28:35 +0300 Subject: [PATCH 06/13] minor change --- src/store/Reducers/sleep/night-quality-reducer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/Reducers/sleep/night-quality-reducer.ts b/src/store/Reducers/sleep/night-quality-reducer.ts index a0b6411..5167167 100644 --- a/src/store/Reducers/sleep/night-quality-reducer.ts +++ b/src/store/Reducers/sleep/night-quality-reducer.ts @@ -8,7 +8,7 @@ import { UPDATE_NIGHT_QUALITY_LOCAL, PUSH_NIGHT_QUALITY_LOCAL, POP_NIGHT_QUALITY_LOCAL -} from 'actions/sleep/night-quality-actions' +} from 'store/actions/sleep/night-quality-actions' const initialState: NightQualityState = { records: new Map(), From 8e55d710e016ebf13f6bc8ca754b2b4be62ec4ba Mon Sep 17 00:00:00 2001 From: = <=> Date: Thu, 3 Sep 2020 15:34:08 +0300 Subject: [PATCH 07/13] Fix bug causing resetting inputs Formik --- ios/Podfile.lock | 6 +- src/components/TextField.tsx | 48 +- src/store/actions/auth/auth-actions.ts | 2 +- .../actions/sleep/night-quality-actions.ts | 4 - yarn.lock | 419 +++++++++--------- 5 files changed, 242 insertions(+), 237 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2ced5de..caebac0 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -184,7 +184,7 @@ PODS: - GoogleUtilities/Logger - GoogleUtilities/UserDefaults (6.7.2): - GoogleUtilities/Logger - - Intercom (7.1.2) + - Intercom (7.1.3) - JKBigInteger2 (0.0.5) - libwebp (1.1.0): - libwebp/demux (= 1.1.0) @@ -880,7 +880,7 @@ SPEC CHECKSUMS: GoogleDataTransport: 9a8a16f79feffc7f42096743de2a7c4815e84020 GoogleDataTransportCCTSupport: 0f39025e8cf51f168711bd3fb773938d7e62ddb5 GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3 - Intercom: ce4923a73543fe70c805635846b6dadf03b0b847 + Intercom: e44b10bbc38ccf6494c76f9bee4e2e3d7d007153 JKBigInteger2: e91672035c42328c48b7dd015b66812ddf40ca9b libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3 nanopb: 18003b5e52dab79db540fe93fe9579f399bd1ccd @@ -958,4 +958,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 7bde1e2e4860e9ae214605a1416d0954a9c0af97 -COCOAPODS: 1.9.3 +COCOAPODS: 1.9.1 diff --git a/src/components/TextField.tsx b/src/components/TextField.tsx index 957355f..8682811 100644 --- a/src/components/TextField.tsx +++ b/src/components/TextField.tsx @@ -1,5 +1,10 @@ import React, { useRef, FC } from 'react' -import { NativeSyntheticEvent, TextInputProps } from 'react-native' +import { + NativeSyntheticEvent, + TextInputProps, + TextInputFocusEventData, + TextInputEndEditingEventData +} from 'react-native' import styled from 'styled-components/native' import translate from '../config/i18n' import colors from '../styles/colors' @@ -15,25 +20,27 @@ interface Props extends TextInputProps { ref?: any } -const TextField: FC = ({ - value, - onBlur, - onEndEditing, - onSubmitEditing, - error, - fieldName, - icon, - ref, - keyboardType, - autoCorrect, - autoCompleteType, - textContentType, - autoCapitalize, - returnKeyType, - enablesReturnKeyAutomatically, - placeholder, - secureTextEntry -}) => { +const TextField: FC = (props: Props) => { + const { + value, + onBlur, + onEndEditing, + onSubmitEditing, + error, + fieldName, + icon, + ref, + keyboardType, + autoCorrect, + autoCompleteType, + textContentType, + autoCapitalize, + returnKeyType, + enablesReturnKeyAutomatically, + placeholder, + secureTextEntry, + tvParallaxTiltAngle + } = props const inputRef: any = useRef(ref) const onFocus = () => { @@ -64,6 +71,7 @@ const TextField: FC = ({ Date: Fri, 4 Sep 2020 15:39:10 +0300 Subject: [PATCH 08/13] Fix tests --- __mocks__/react-native-iphone-x-helper.ts | 3 ++- __mocks__/react-native-ultimate-config.ts | 3 +++ src/components/IAPComponents/PerkList.spec.tsx | 6 ++++++ .../__tests__/SettingRow.spec.tsx | 5 +++++ .../__tests__/VersionInformation.test.tsx | 5 +++++ src/components/__tests__/SvgIcon.test.tsx | 7 +++++++ .../__tests__/TranslatedText.test.tsx | 5 +++++ .../Reducers/api-reducer/api-reducer.spec.ts | 6 ++++++ .../Reducers/auth-reducer/auth-reducer.spec.ts | 16 ++++++++++++++++ src/store/Reducers/modal/modal-reducer.spec.ts | 5 +++++ .../sleep/night-quality-reducer.spec.ts | 18 ++++++++++++++++++ src/store/Reducers/user/user-reducer.spec.ts | 7 +++++++ src/store/actions/habit/habit-actions.spec.ts | 6 ++++++ .../manual-sleep/manual-sleep-actions.spec.ts | 5 +++++ 14 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 __mocks__/react-native-ultimate-config.ts create mode 100644 src/store/Reducers/sleep/night-quality-reducer.spec.ts diff --git a/__mocks__/react-native-iphone-x-helper.ts b/__mocks__/react-native-iphone-x-helper.ts index 73676f7..e603dfb 100644 --- a/__mocks__/react-native-iphone-x-helper.ts +++ b/__mocks__/react-native-iphone-x-helper.ts @@ -1,4 +1,5 @@ jest.mock('react-native-iphone-x-helper', () => ({ getStatusBarHeight: jest.fn(), - isIphoneX: () => true + ifIphoneX: jest.fn(), + isIphoneX: jest.fn() })) diff --git a/__mocks__/react-native-ultimate-config.ts b/__mocks__/react-native-ultimate-config.ts new file mode 100644 index 0000000..b479643 --- /dev/null +++ b/__mocks__/react-native-ultimate-config.ts @@ -0,0 +1,3 @@ +jest.mock("react-native-ultimate-config", () => ({ + +})) \ No newline at end of file diff --git a/src/components/IAPComponents/PerkList.spec.tsx b/src/components/IAPComponents/PerkList.spec.tsx index de8d729..2d1c13c 100644 --- a/src/components/IAPComponents/PerkList.spec.tsx +++ b/src/components/IAPComponents/PerkList.spec.tsx @@ -3,6 +3,12 @@ import React from 'react' import { matchComponentToSnapshot } from '@helpers/snapshot' import PerkList from './PerkList' +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + ifIphoneX: jest.fn(), + isIphoneX: jest.fn() +})) + describe('', () => { it('it renders correctly', () => { matchComponentToSnapshot() diff --git a/src/components/SettingsSpecific/__tests__/SettingRow.spec.tsx b/src/components/SettingsSpecific/__tests__/SettingRow.spec.tsx index cd1284d..70da96d 100644 --- a/src/components/SettingsSpecific/__tests__/SettingRow.spec.tsx +++ b/src/components/SettingsSpecific/__tests__/SettingRow.spec.tsx @@ -4,6 +4,11 @@ import React from 'react' import { matchComponentToSnapshot } from '@helpers/snapshot' import SettingRow from '../settingRow' +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + isIphoneX: () => true +})) + describe('', () => { it('should render correctly', () => { matchComponentToSnapshot( diff --git a/src/components/SettingsSpecific/__tests__/VersionInformation.test.tsx b/src/components/SettingsSpecific/__tests__/VersionInformation.test.tsx index 4ba6345..18f53a1 100644 --- a/src/components/SettingsSpecific/__tests__/VersionInformation.test.tsx +++ b/src/components/SettingsSpecific/__tests__/VersionInformation.test.tsx @@ -15,6 +15,11 @@ jest.mock('react-native-device-info', () => ({ getDevice: jest.fn() })) +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + isIphoneX: () => true +})) + describe('', () => { it('Should render correctly', () => { matchComponentToSnapshot() diff --git a/src/components/__tests__/SvgIcon.test.tsx b/src/components/__tests__/SvgIcon.test.tsx index 00b7c9b..9e0dd19 100644 --- a/src/components/__tests__/SvgIcon.test.tsx +++ b/src/components/__tests__/SvgIcon.test.tsx @@ -3,6 +3,13 @@ import * as React from 'react' import SvgIcon from '../SvgIcon' import { matchComponentToSnapshot } from '@helpers/snapshot' +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + ifIphoneX: jest.fn(), + isIphoneX: jest.fn() +})) + + describe('', () => { it('it renders correctly', () => { matchComponentToSnapshot( diff --git a/src/components/__tests__/TranslatedText.test.tsx b/src/components/__tests__/TranslatedText.test.tsx index 3105e08..5ad9577 100644 --- a/src/components/__tests__/TranslatedText.test.tsx +++ b/src/components/__tests__/TranslatedText.test.tsx @@ -8,6 +8,11 @@ jest.mock('moment', () => ({ locale: () => {} })) +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + isIphoneX: () => true +})) + describe('', () => { it('it renders correctly', () => { matchComponentToSnapshot( diff --git a/src/store/Reducers/api-reducer/api-reducer.spec.ts b/src/store/Reducers/api-reducer/api-reducer.spec.ts index 6888b24..f0fe986 100644 --- a/src/store/Reducers/api-reducer/api-reducer.spec.ts +++ b/src/store/Reducers/api-reducer/api-reducer.spec.ts @@ -5,6 +5,12 @@ import { import reducer, { initialState } from './api-reducer' import { ResponseBase } from '../../../Types/State/api-state' +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + ifIphoneX: jest.fn(), + isIphoneX: jest.fn() +})) + const fitbitMock: ResponseBase = { enabled: true } diff --git a/src/store/Reducers/auth-reducer/auth-reducer.spec.ts b/src/store/Reducers/auth-reducer/auth-reducer.spec.ts index 534900d..8c65085 100644 --- a/src/store/Reducers/auth-reducer/auth-reducer.spec.ts +++ b/src/store/Reducers/auth-reducer/auth-reducer.spec.ts @@ -10,9 +10,25 @@ import { } from '@actions/auth/auth-actions' import reducer, { initialState } from './auth-reducer' +jest.mock('react-native', () => ({ + NativeModules: { + RNCNetInfo: jest.fn() + }, + StyleSheet: { + hairlineWidth: 10 + } +})) + NativeModules.RNCNetInfo = RNCNetInfoMock + jest.mock('@react-native-community/netinfo', () => ({})) +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + ifIphoneX: jest.fn(), + isIphoneX: jest.fn() +})) + describe('Auth reducer', () => { it('should return the initial state', () => { expect(reducer(undefined, {})).toEqual(initialState) diff --git a/src/store/Reducers/modal/modal-reducer.spec.ts b/src/store/Reducers/modal/modal-reducer.spec.ts index b1cea7b..bf94c0c 100644 --- a/src/store/Reducers/modal/modal-reducer.spec.ts +++ b/src/store/Reducers/modal/modal-reducer.spec.ts @@ -1,6 +1,11 @@ import { TOGGLE_RATING_MODAL } from '@actions/modal/modal-actions' import reducer, { initialState } from './modal-reducer' +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + isIphoneX: () => true +})) + describe('Coaching notification reducer', () => { it('should return the initial state', () => { expect(reducer(undefined, {})).toEqual(initialState) diff --git a/src/store/Reducers/sleep/night-quality-reducer.spec.ts b/src/store/Reducers/sleep/night-quality-reducer.spec.ts new file mode 100644 index 0000000..63a7f71 --- /dev/null +++ b/src/store/Reducers/sleep/night-quality-reducer.spec.ts @@ -0,0 +1,18 @@ +import NightQualityReducer from '@reducers/sleep/night-quality-reducer' +import { NightQualityState } from 'Types/Sleep/NightQuality' + +const initialState: NightQualityState = { + records: new Map(), + localRecords: new Map() +} + +describe('Night Quality Reducer', () => { + it('should return initial state', () => { + expect( + NightQualityReducer( + { records: new Map(), localRecords: new Map() }, + { type: 'NOTHING' } + ) + ).toEqual(initialState) + }) +}) diff --git a/src/store/Reducers/user/user-reducer.spec.ts b/src/store/Reducers/user/user-reducer.spec.ts index 7048efa..0bd54c3 100644 --- a/src/store/Reducers/user/user-reducer.spec.ts +++ b/src/store/Reducers/user/user-reducer.spec.ts @@ -12,6 +12,13 @@ jest.mock('react-native', () => ({ } })) +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + ifIphoneX: jest.fn(), + isIphoneX: jest.fn() +})) + + describe('User reducer', () => { it('should return the initial state', () => { expect(reducer(undefined, { type: '' })).toEqual(initialState) diff --git a/src/store/actions/habit/habit-actions.spec.ts b/src/store/actions/habit/habit-actions.spec.ts index 0a552d4..44b971e 100644 --- a/src/store/actions/habit/habit-actions.spec.ts +++ b/src/store/actions/habit/habit-actions.spec.ts @@ -40,6 +40,12 @@ jest.mock('moment', () => () => ({ toISOString: () => '2020-05-07T21:00:00.000Z' })) +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + ifIphoneX: jest.fn(), + isIphoneX: jest.fn() +})) + const middlewares = [thunk] const startOfTodayString = '2020-05-07T21:00:00.000Z' diff --git a/src/store/actions/manual-sleep/manual-sleep-actions.spec.ts b/src/store/actions/manual-sleep/manual-sleep-actions.spec.ts index 4229799..2a83e59 100644 --- a/src/store/actions/manual-sleep/manual-sleep-actions.spec.ts +++ b/src/store/actions/manual-sleep/manual-sleep-actions.spec.ts @@ -10,6 +10,11 @@ const testValues = { end: { h: 12, m: 0 } } +jest.mock('react-native-iphone-x-helper', () => ({ + getStatusBarHeight: jest.fn(), + isIphoneX: () => true +})) + describe('Manual sleep actions', () => { it('should create an action to set values', () => { const expectedAction = { From 06a91909dd8401b1095cace0f47092358b805115 Mon Sep 17 00:00:00 2001 From: = <=> Date: Mon, 7 Sep 2020 21:14:03 +0300 Subject: [PATCH 09/13] Update unit-tests for Night Quality + update fix for using Night Quality only when logged in --- src/Types/Sleep/NightQuality.ts | 2 +- .../sleep/night-quality-reducer.spec.ts | 81 ++++++++++++++++++- .../Reducers/sleep/night-quality-reducer.ts | 50 +++++++----- .../night-quality-selector.ts | 34 +++++--- .../actions/sleep/night-quality-actions.ts | 75 +++++++++-------- 5 files changed, 169 insertions(+), 73 deletions(-) diff --git a/src/Types/Sleep/NightQuality.ts b/src/Types/Sleep/NightQuality.ts index 25c1ca2..dc1ad73 100644 --- a/src/Types/Sleep/NightQuality.ts +++ b/src/Types/Sleep/NightQuality.ts @@ -1,6 +1,6 @@ export interface NightQualityState { records: Map - localRecords: Map + // localRecords: Map // --- CAN DELETE --- } export interface NightQuality { diff --git a/src/store/Reducers/sleep/night-quality-reducer.spec.ts b/src/store/Reducers/sleep/night-quality-reducer.spec.ts index 63a7f71..ac502cf 100644 --- a/src/store/Reducers/sleep/night-quality-reducer.spec.ts +++ b/src/store/Reducers/sleep/night-quality-reducer.spec.ts @@ -1,18 +1,91 @@ import NightQualityReducer from '@reducers/sleep/night-quality-reducer' -import { NightQualityState } from 'Types/Sleep/NightQuality' +import { NightQualityState, NightQuality } from 'Types/Sleep/NightQuality' +import { + updateNightQuality, + pushNightQuality, + loadNightQualityFromCloud +} from 'store/actions/sleep/night-quality-actions' const initialState: NightQualityState = { - records: new Map(), - localRecords: new Map() + records: new Map() + // localRecords: new Map() // --- CAN DELETE --- } describe('Night Quality Reducer', () => { it('should return initial state', () => { expect( NightQualityReducer( - { records: new Map(), localRecords: new Map() }, + { + records: new Map() + // localRecords: new Map() // --- CAN DELETE --- + }, { type: 'NOTHING' } ) ).toEqual(initialState) }) + + const inputPayload: NightQuality = { + id: 'uniq_id', + date: 'uniq_date', + rating: 3 + } + + it('should handle UPDATE_NIGHT_QUALITY', () => { + const records = new Map().set(inputPayload.date, inputPayload) + const newInputPayload: NightQuality = { + id: 'new_uniq_id', + date: inputPayload.date, + rating: 5 + } + const expected: NightQualityState = { + records: records.set(newInputPayload.date, newInputPayload) + // localRecords: new Map() // --- CAN DELETE --- + } + + expect( + NightQualityReducer( + { + records + // localRecords: new Map() // --- CAN DELETE --- + }, + updateNightQuality(newInputPayload) + ) + ).toEqual(expected) + }) + + it('should handle PUSH_NIGHT_QUALITY', () => { + const expected: NightQualityState = { + records: new Map().set(inputPayload.date, inputPayload) + // localRecords: new Map() // --- CAN DELETE --- + } + + expect( + NightQualityReducer( + { + records: new Map() + // localRecords: new Map() // --- CAN DELETE --- + }, + pushNightQuality(inputPayload) + ) + ).toEqual(expected) + }) + + it('should handle LOAD_NIGHT_QUALITY_FROM_CLOUD', () => { + const payload = new Map().set(inputPayload.date, inputPayload) + + const expected: NightQualityState = { + records: payload + // localRecords: new Map() // --- CAN DELETE --- + } + + expect( + NightQualityReducer( + { + records: new Map() + // localRecords: new Map() // --- CAN DELETE --- + }, + loadNightQualityFromCloud(payload) + ) + ).toEqual(expected) + }) }) diff --git a/src/store/Reducers/sleep/night-quality-reducer.ts b/src/store/Reducers/sleep/night-quality-reducer.ts index 5167167..e3f1b7d 100644 --- a/src/store/Reducers/sleep/night-quality-reducer.ts +++ b/src/store/Reducers/sleep/night-quality-reducer.ts @@ -1,18 +1,21 @@ import ReduxAction from 'Types/ReduxActions' import { NightQualityState } from 'Types/Sleep/NightQuality' -import { produce } from 'immer' +import { produce, enableMapSet } from 'immer' import { UPDATE_NIGHT_QUALITY, PUSH_NIGHT_QUALITY, - LOAD_NIGHT_QUALITY_FROM_CLOUD, - UPDATE_NIGHT_QUALITY_LOCAL, - PUSH_NIGHT_QUALITY_LOCAL, - POP_NIGHT_QUALITY_LOCAL + LOAD_NIGHT_QUALITY_FROM_CLOUD + // --- CAN DELETE --- + // UPDATE_NIGHT_QUALITY_LOCAL, + // PUSH_NIGHT_QUALITY_LOCAL, + // POP_NIGHT_QUALITY_LOCAL } from 'store/actions/sleep/night-quality-actions' +enableMapSet() + const initialState: NightQualityState = { - records: new Map(), - localRecords: new Map() + records: new Map() + // localRecords: new Map() // --- CAN DELETE --- } const reducer = produce((draft: NightQualityState, action: ReduxAction) => { @@ -31,21 +34,24 @@ const reducer = produce((draft: NightQualityState, action: ReduxAction) => { draft.records = payload break - case UPDATE_NIGHT_QUALITY_LOCAL: - draft.localRecords.set(payload.date, payload) - break - - case PUSH_NIGHT_QUALITY_LOCAL: - draft.localRecords.set(payload.date, payload) - break - - case POP_NIGHT_QUALITY_LOCAL: - const poppedMap = Array.from(draft.localRecords).slice( - 1, - draft.localRecords.size - ) - draft.localRecords = new Map(poppedMap) - break + // --- CAN DELETE --- + // case UPDATE_NIGHT_QUALITY_LOCAL: + // draft.localRecords.set(payload.date, payload) + // break + + // --- CAN DELETE --- + // case PUSH_NIGHT_QUALITY_LOCAL: + // draft.localRecords.set(payload.date, payload) + // break + + // --- CAN DELETE --- + // case POP_NIGHT_QUALITY_LOCAL: + // const poppedMap = Array.from(draft.localRecords).slice( + // 1, + // draft.localRecords.size + // ) + // draft.localRecords = new Map(poppedMap) + // break } }, initialState) diff --git a/src/store/Selectors/night-quality-selectors/night-quality-selector.ts b/src/store/Selectors/night-quality-selectors/night-quality-selector.ts index 6b85287..a83b312 100644 --- a/src/store/Selectors/night-quality-selectors/night-quality-selector.ts +++ b/src/store/Selectors/night-quality-selectors/night-quality-selector.ts @@ -1,25 +1,35 @@ import { createSelector } from 'reselect' import { State } from 'Types/State' import { NightQualityState } from 'Types/Sleep/NightQuality' -import { UserState } from 'Types/UserState' +// import { UserState } from 'Types/UserState' // --- CAN DELETE --- const getNightQualityState = (state: State) => state.nightQuality -const getUserState = (state: State) => state.user +// const getUserState = (state: State) => state.user // --- CAN DELETE --- const getProps = (state: State, { date }: { date: string }) => date +// --- CAN DELETE --- +// export const makeGetRatingOnDate = () => +// createSelector( +// getNightQualityState, +// getUserState, +// getProps, +// ( +// nightQualityState: NightQualityState, +// userState: UserState, +// date: string +// ) => { +// const { authenticated } = userState +// if (authenticated) return nightQualityState.records.get(date) + +// return nightQualityState.localRecords.get(date) +// } +// ) + export const makeGetRatingOnDate = () => createSelector( getNightQualityState, - getUserState, getProps, - ( - nightQualityState: NightQualityState, - userState: UserState, - date: string - ) => { - const { authenticated } = userState - if (authenticated) return nightQualityState.records.get(date) - - return nightQualityState.localRecords.get(date) + (nightQualityState: NightQualityState, date: string) => { + return nightQualityState.records.get(date) } ) diff --git a/src/store/actions/sleep/night-quality-actions.ts b/src/store/actions/sleep/night-quality-actions.ts index c028cee..4fcecea 100644 --- a/src/store/actions/sleep/night-quality-actions.ts +++ b/src/store/actions/sleep/night-quality-actions.ts @@ -27,19 +27,22 @@ export const pushNightQuality = (nightQuality: NightQuality) => ({ payload: nightQuality }) -export const updateNightQualityLocally = (nightQuality: NightQuality) => ({ - type: UPDATE_NIGHT_QUALITY_LOCAL, - payload: nightQuality -}) - -export const pushNightQualityLocally = (nightQuality: NightQuality) => ({ - type: PUSH_NIGHT_QUALITY_LOCAL, - payload: nightQuality -}) - -export const popNightQualityLocally = () => ({ - type: POP_NIGHT_QUALITY_LOCAL -}) +// --- CAN DELETE --- +// export const updateNightQualityLocally = (nightQuality: NightQuality) => ({ +// type: UPDATE_NIGHT_QUALITY_LOCAL, +// payload: nightQuality +// }) + +// --- CAN DELETE --- +// export const pushNightQualityLocally = (nightQuality: NightQuality) => ({ +// type: PUSH_NIGHT_QUALITY_LOCAL, +// payload: nightQuality +// }) + +// --- CAN DELETE --- +// export const popNightQualityLocally = () => ({ +// type: POP_NIGHT_QUALITY_LOCAL +// }) export const loadNightQualityFromCloud = ( nightQualityFromCloud: Map @@ -91,7 +94,7 @@ export const getNightRatingsFromCloud = (username?: string) => async ( } } -const convertNightQualityFromCloudToMap = ( +export const convertNightQualityFromCloudToMap = ( cloudNightRatings: Array ) => { const map = new Map() @@ -112,7 +115,7 @@ export const rateNight = ({ id, rating, date }: NightQuality) => async ( nightQuality } = getState() - date = date && date.length > 0 ? date : '' + date = date && date.length > 0 ? date : 'undefined' //Because aws doesn't accept empty string const newNightRating: NightQuality = { id, @@ -155,22 +158,25 @@ export const rateNight = ({ id, rating, date }: NightQuality) => async ( await dispatch(pushNightQuality(newNightRating)) } - } else { - // If record already exists, we update it - if (checkRecordExists(nightQuality, date)) { - await dispatch(updateNightQualityLocally(newNightRating)) - } - // If not, we handle it as local data - else { - // If the new night rating will break the size, we pop the 1st element (the oldest night rating) so the array always remains 31 elements - if (checkIfWillExceedQuantity(nightQuality)) { - await dispatch(popNightQualityLocally()) - } - - // Push the new one in as the 31st element - await dispatch(pushNightQualityLocally(newNightRating)) - } } + + // --- CAN DELETE --- + // else { + // // If record already exists, we update it + // if (checkRecordExists(nightQuality, date)) { + // await dispatch(updateNightQualityLocally(newNightRating)) + // } + // // If not, we handle it as local data + // else { + // // If the new night rating will break the size, we pop the 1st element (the oldest night rating) so the array always remains 31 elements + // if (checkIfWillExceedQuantity(nightQuality)) { + // await dispatch(popNightQualityLocally()) + // } + + // // Push the new one in as the 31st element + // await dispatch(pushNightQualityLocally(newNightRating)) + // } + // } } catch (err) { console.log('rateNight', err) } @@ -183,7 +189,8 @@ const checkRecordExists = ({ records }: NightQualityState, date: string) => { return records.has(date) } -const checkIfWillExceedQuantity = ({ records }: NightQualityState) => { - // return records.length === 31 - return records.size === 31 -} +// --- CAN DELETE --- +// const checkIfWillExceedQuantity = ({ records }: NightQualityState) => { +// // return records.length === 31 +// return records.size === 31 +// } From 4897f0735f6aa9cfdf5f143cd961e6f5424c064d Mon Sep 17 00:00:00 2001 From: = <=> Date: Mon, 7 Sep 2020 21:15:40 +0300 Subject: [PATCH 10/13] minor commit because missing file from last commit --- .../sleep/night-quality-actions.spec.ts | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 src/store/actions/sleep/night-quality-actions.spec.ts diff --git a/src/store/actions/sleep/night-quality-actions.spec.ts b/src/store/actions/sleep/night-quality-actions.spec.ts new file mode 100644 index 0000000..eb62561 --- /dev/null +++ b/src/store/actions/sleep/night-quality-actions.spec.ts @@ -0,0 +1,96 @@ +import { + getNightRatingsFromCloud, + loadNightQualityFromCloud, + convertNightQualityFromCloudToMap, + rateNight, + updateNightQuality +} from './night-quality-actions' +import configureMockStore from 'redux-mock-store' +import thunk from 'redux-thunk' +import { AnyAction } from 'redux' +import { NightQuality } from 'Types/Sleep/NightQuality' + +const middlewares = [thunk] +const mockStore = configureMockStore(middlewares) + +const mockedRemoteData = { + data: { + listNightRatings: { + items: [ + { date: 'uniq_date_1', id: 'uniq_id_1', rating: 0 }, + { date: 'uniq_date_2', id: 'uniq_id_2', rating: 1 }, + { date: 'uniq_date_3', id: 'uniq_id_3', rating: 2 } + ] + } + } +} + +jest.mock('aws-amplify', () => ({ + API: { + graphql: () => mockedRemoteData + }, + + graphqlOperation: jest.fn() +})) + +describe('Night Quality Action', () => { + it('should handle getNightRatingsFromCloud function', () => { + const store = mockStore({ + user: { + authenticated: true, + username: 'uniq_username' + }, + nightQuality: { + records: new Map() + // localRecords: new Map() // --- CAN DELETE --- + } + }) + + return store + .dispatch((getNightRatingsFromCloud())) + .then(() => { + const actions = store.getActions() + + expect(actions[0]).toEqual( + loadNightQualityFromCloud( + convertNightQualityFromCloudToMap( + mockedRemoteData.data.listNightRatings.items + ) + ) + ) + }) + }) + + it('should handle rateNight function', () => { + const inputNightQuality: NightQuality = { + id: 'uniq_id_1', + date: 'uniq_date_1', + rating: 0 + } + const records: Map = new Map().set( + inputNightQuality.date, + inputNightQuality + ) + + const store = mockStore({ + user: { + authenticated: true, + username: 'uniq_username' + }, + nightQuality: { + records: records + // localRecords: new Map() // --- CAN DELETE --- + } + }) + + const updateNight: NightQuality = { ...inputNightQuality, rating: 3 } + + return store + .dispatch((rateNight(updateNight))) + .then(() => { + const actions = store.getActions() + + expect(actions[0]).toEqual(updateNightQuality(updateNight)) + }) + }) +}) From 4b7b4c7e14f7e63b1d7568d6f6c5b703e0622cf0 Mon Sep 17 00:00:00 2001 From: = <=> Date: Mon, 7 Sep 2020 22:38:46 +0300 Subject: [PATCH 11/13] Update a fix for a bug causing creating different unique id each time rating a night + only work when logged in + clean code --- src/Types/Sleep/NightQuality.ts | 1 - src/components/Buttons/RatingButton.tsx | 8 +- src/components/Charts/SleepChart.tsx | 1 + src/components/DayStrip.tsx | 17 +++-- src/components/clock/NightRating.tsx | 1 - src/screens/main/main.tsx | 6 ++ .../sleep/night-quality-reducer.spec.ts | 8 -- .../Reducers/sleep/night-quality-reducer.ts | 24 ------ .../night-quality-selector.ts | 20 ----- .../sleep/night-quality-actions.spec.ts | 11 ++- .../actions/sleep/night-quality-actions.ts | 76 +++++-------------- 11 files changed, 46 insertions(+), 127 deletions(-) diff --git a/src/Types/Sleep/NightQuality.ts b/src/Types/Sleep/NightQuality.ts index dc1ad73..b28b539 100644 --- a/src/Types/Sleep/NightQuality.ts +++ b/src/Types/Sleep/NightQuality.ts @@ -1,6 +1,5 @@ export interface NightQualityState { records: Map - // localRecords: Map // --- CAN DELETE --- } export interface NightQuality { diff --git a/src/components/Buttons/RatingButton.tsx b/src/components/Buttons/RatingButton.tsx index 5eca8d0..c7b01e7 100644 --- a/src/components/Buttons/RatingButton.tsx +++ b/src/components/Buttons/RatingButton.tsx @@ -9,7 +9,6 @@ import ScalingButton from './ScalingButton' import { rateNight } from 'store/actions/sleep/night-quality-actions' import { NightQuality } from 'Types/Sleep/NightQuality' import { getRatingDate } from 'store/Selectors/ModalSelectors' -import { v4 } from 'uuid' type Props = { selected: boolean @@ -25,12 +24,7 @@ const RatingButton: FC = ({ value, title, icon, color }) => { const handlePress = () => { dispatch(rateDay(value)) - const nightQuality: NightQuality = { - id: v4(), - rating: value, - date: ratingDate && ratingDate.length > 0 ? ratingDate : 'unknown' - } - dispatch(rateNight(nightQuality)) + dispatch(rateNight({ rating: value, date: ratingDate })) } return ( diff --git a/src/components/Charts/SleepChart.tsx b/src/components/Charts/SleepChart.tsx index 229f24f..fc607c3 100644 --- a/src/components/Charts/SleepChart.tsx +++ b/src/components/Charts/SleepChart.tsx @@ -154,6 +154,7 @@ type NormalizedDay = Day & { const normalizeSleepData = (days: Day[]): NormalizedDay[] => { const normalized = days.map((day) => { + day.night = day.night ? day.night : [] // Some nights return as undefined const normalizedNights = day.night.map((night) => { const trueDate = moment(day.date) diff --git a/src/components/DayStrip.tsx b/src/components/DayStrip.tsx index 232d71b..0d76d23 100644 --- a/src/components/DayStrip.tsx +++ b/src/components/DayStrip.tsx @@ -40,15 +40,16 @@ const DayStrip: FC = () => { {moment(item.date).format('DD.MM.')} + - + - + ) } @@ -82,7 +83,6 @@ const Container = styled.View` const Segments = styled(FlatList)` width: ${WIDTH}px; - height: ${dayWidth + 30}px; margin: 20px 0px; padding: 10px 0px; ` @@ -107,6 +107,13 @@ const Segment = styled.TouchableOpacity` : props.theme.PRIMARY_BACKGROUND_COLOR}; ` +const RatingSegment = styled.View` + width: ${dayWidth}px; + flex-direction: column; + justify-content: center; + align-items: center; +` + const DateText = styled.Text` font-size: 12px; color: ${(props: SegmentProps) => @@ -132,7 +139,3 @@ const DateNumber = styled.Text` const Spacer = styled.View` height: ${spacerHeight}px; ` -const NightRatingHolder = styled.View` - justify-content: center; - align-items: center; -` diff --git a/src/components/clock/NightRating.tsx b/src/components/clock/NightRating.tsx index 0e2b7da..ed5130c 100644 --- a/src/components/clock/NightRating.tsx +++ b/src/components/clock/NightRating.tsx @@ -23,7 +23,6 @@ const NightRating: FC = ({ date, unClickable, height, width }) => { const ratingDate = useSelector((state: State) => getRatingOnDate(state, { date }) ) - const { icon, color } = getRating(ratingDate?.rating) const dispatch = useDispatch() diff --git a/src/screens/main/main.tsx b/src/screens/main/main.tsx index 4e323c0..d595123 100644 --- a/src/screens/main/main.tsx +++ b/src/screens/main/main.tsx @@ -28,12 +28,15 @@ import NewHabitModal from '@components/modals/HabitModal/NewHabitModal' import { SafeAreaView } from '@components/Primitives/Primitives' import TopInfo from '@components/TopInfo' import colors from '../../styles/colors' +import { getAuthState } from 'store/selectors/auth-selectors/auth-selectors' +import { getNightRatingsFromCloud } from 'store/actions/sleep/night-quality-actions' const MainScreen = () => { const isLoadingSleepData = useSelector(getHealthKitLoading) const isLoadingFitbit = useSelector(getLoadingFitbit) const isLoadingGoogleFit = useSelector(getLoadingGoogleFit) const dispatch = useDispatch() + const authenticated = useSelector(getAuthState) useNotificationEventHandlers() @@ -48,6 +51,9 @@ const MainScreen = () => { const checkSleepData = async () => { await dispatch(fetchSleepData()) await dispatch(updateCalendar()) + if (authenticated) { + await dispatch(getNightRatingsFromCloud()) + } } return ( diff --git a/src/store/Reducers/sleep/night-quality-reducer.spec.ts b/src/store/Reducers/sleep/night-quality-reducer.spec.ts index ac502cf..eee9d6b 100644 --- a/src/store/Reducers/sleep/night-quality-reducer.spec.ts +++ b/src/store/Reducers/sleep/night-quality-reducer.spec.ts @@ -8,7 +8,6 @@ import { const initialState: NightQualityState = { records: new Map() - // localRecords: new Map() // --- CAN DELETE --- } describe('Night Quality Reducer', () => { @@ -17,7 +16,6 @@ describe('Night Quality Reducer', () => { NightQualityReducer( { records: new Map() - // localRecords: new Map() // --- CAN DELETE --- }, { type: 'NOTHING' } ) @@ -39,14 +37,12 @@ describe('Night Quality Reducer', () => { } const expected: NightQualityState = { records: records.set(newInputPayload.date, newInputPayload) - // localRecords: new Map() // --- CAN DELETE --- } expect( NightQualityReducer( { records - // localRecords: new Map() // --- CAN DELETE --- }, updateNightQuality(newInputPayload) ) @@ -56,14 +52,12 @@ describe('Night Quality Reducer', () => { it('should handle PUSH_NIGHT_QUALITY', () => { const expected: NightQualityState = { records: new Map().set(inputPayload.date, inputPayload) - // localRecords: new Map() // --- CAN DELETE --- } expect( NightQualityReducer( { records: new Map() - // localRecords: new Map() // --- CAN DELETE --- }, pushNightQuality(inputPayload) ) @@ -75,14 +69,12 @@ describe('Night Quality Reducer', () => { const expected: NightQualityState = { records: payload - // localRecords: new Map() // --- CAN DELETE --- } expect( NightQualityReducer( { records: new Map() - // localRecords: new Map() // --- CAN DELETE --- }, loadNightQualityFromCloud(payload) ) diff --git a/src/store/Reducers/sleep/night-quality-reducer.ts b/src/store/Reducers/sleep/night-quality-reducer.ts index e3f1b7d..d3efaed 100644 --- a/src/store/Reducers/sleep/night-quality-reducer.ts +++ b/src/store/Reducers/sleep/night-quality-reducer.ts @@ -5,17 +5,12 @@ import { UPDATE_NIGHT_QUALITY, PUSH_NIGHT_QUALITY, LOAD_NIGHT_QUALITY_FROM_CLOUD - // --- CAN DELETE --- - // UPDATE_NIGHT_QUALITY_LOCAL, - // PUSH_NIGHT_QUALITY_LOCAL, - // POP_NIGHT_QUALITY_LOCAL } from 'store/actions/sleep/night-quality-actions' enableMapSet() const initialState: NightQualityState = { records: new Map() - // localRecords: new Map() // --- CAN DELETE --- } const reducer = produce((draft: NightQualityState, action: ReduxAction) => { @@ -33,25 +28,6 @@ const reducer = produce((draft: NightQualityState, action: ReduxAction) => { case LOAD_NIGHT_QUALITY_FROM_CLOUD: draft.records = payload break - - // --- CAN DELETE --- - // case UPDATE_NIGHT_QUALITY_LOCAL: - // draft.localRecords.set(payload.date, payload) - // break - - // --- CAN DELETE --- - // case PUSH_NIGHT_QUALITY_LOCAL: - // draft.localRecords.set(payload.date, payload) - // break - - // --- CAN DELETE --- - // case POP_NIGHT_QUALITY_LOCAL: - // const poppedMap = Array.from(draft.localRecords).slice( - // 1, - // draft.localRecords.size - // ) - // draft.localRecords = new Map(poppedMap) - // break } }, initialState) diff --git a/src/store/Selectors/night-quality-selectors/night-quality-selector.ts b/src/store/Selectors/night-quality-selectors/night-quality-selector.ts index a83b312..6a77084 100644 --- a/src/store/Selectors/night-quality-selectors/night-quality-selector.ts +++ b/src/store/Selectors/night-quality-selectors/night-quality-selector.ts @@ -1,30 +1,10 @@ import { createSelector } from 'reselect' import { State } from 'Types/State' import { NightQualityState } from 'Types/Sleep/NightQuality' -// import { UserState } from 'Types/UserState' // --- CAN DELETE --- const getNightQualityState = (state: State) => state.nightQuality -// const getUserState = (state: State) => state.user // --- CAN DELETE --- const getProps = (state: State, { date }: { date: string }) => date -// --- CAN DELETE --- -// export const makeGetRatingOnDate = () => -// createSelector( -// getNightQualityState, -// getUserState, -// getProps, -// ( -// nightQualityState: NightQualityState, -// userState: UserState, -// date: string -// ) => { -// const { authenticated } = userState -// if (authenticated) return nightQualityState.records.get(date) - -// return nightQualityState.localRecords.get(date) -// } -// ) - export const makeGetRatingOnDate = () => createSelector( getNightQualityState, diff --git a/src/store/actions/sleep/night-quality-actions.spec.ts b/src/store/actions/sleep/night-quality-actions.spec.ts index eb62561..6da763b 100644 --- a/src/store/actions/sleep/night-quality-actions.spec.ts +++ b/src/store/actions/sleep/night-quality-actions.spec.ts @@ -42,7 +42,6 @@ describe('Night Quality Action', () => { }, nightQuality: { records: new Map() - // localRecords: new Map() // --- CAN DELETE --- } }) @@ -79,18 +78,22 @@ describe('Night Quality Action', () => { }, nightQuality: { records: records - // localRecords: new Map() // --- CAN DELETE --- } }) - const updateNight: NightQuality = { ...inputNightQuality, rating: 3 } + const updateNight = { + date: inputNightQuality.date, + rating: inputNightQuality.rating + } return store .dispatch((rateNight(updateNight))) .then(() => { const actions = store.getActions() - expect(actions[0]).toEqual(updateNightQuality(updateNight)) + expect(actions[0]).toEqual( + updateNightQuality({ ...updateNight, id: inputNightQuality.id }) + ) }) }) }) diff --git a/src/store/actions/sleep/night-quality-actions.ts b/src/store/actions/sleep/night-quality-actions.ts index 4fcecea..6349d60 100644 --- a/src/store/actions/sleep/night-quality-actions.ts +++ b/src/store/actions/sleep/night-quality-actions.ts @@ -9,6 +9,7 @@ import { UpdateNightRatingInput } from 'API' import { listNightRatings } from 'graphql/queries' +import { v4 } from 'uuid' export const UPDATE_NIGHT_QUALITY = 'UPDATE_NIGHT_QUALITY' export const PUSH_NIGHT_QUALITY = 'PUSH_NIGHT_QUALITY' @@ -27,23 +28,6 @@ export const pushNightQuality = (nightQuality: NightQuality) => ({ payload: nightQuality }) -// --- CAN DELETE --- -// export const updateNightQualityLocally = (nightQuality: NightQuality) => ({ -// type: UPDATE_NIGHT_QUALITY_LOCAL, -// payload: nightQuality -// }) - -// --- CAN DELETE --- -// export const pushNightQualityLocally = (nightQuality: NightQuality) => ({ -// type: PUSH_NIGHT_QUALITY_LOCAL, -// payload: nightQuality -// }) - -// --- CAN DELETE --- -// export const popNightQualityLocally = () => ({ -// type: POP_NIGHT_QUALITY_LOCAL -// }) - export const loadNightQualityFromCloud = ( nightQualityFromCloud: Map ) => ({ @@ -106,10 +90,13 @@ export const convertNightQualityFromCloudToMap = ( return map } -export const rateNight = ({ id, rating, date }: NightQuality) => async ( - dispatch: Dispatch, - getState: GetState -) => { +export const rateNight = ({ + rating, + date +}: { + rating: number + date: string | undefined +}) => async (dispatch: Dispatch, getState: GetState) => { const { user: { authenticated, username }, nightQuality @@ -117,18 +104,18 @@ export const rateNight = ({ id, rating, date }: NightQuality) => async ( date = date && date.length > 0 ? date : 'undefined' //Because aws doesn't accept empty string - const newNightRating: NightQuality = { - id, - rating, - date - } - try { // Handle cloud update if user is logged in if (authenticated) { // We check to see if the rating for date already exists // If it exists, we update its data in the cloud if (checkRecordExists(nightQuality, date)) { + const newNightRating: NightQuality = { + id: nightQuality.records.get(date)?.id as string, + rating, + date + } + const updateNightRatingInput: UpdateNightRatingInput = { date, userId: username as string, @@ -149,7 +136,13 @@ export const rateNight = ({ id, rating, date }: NightQuality) => async ( date, userId: username as string, rating, - id + id: v4() + } + + const newNightRating: NightQuality = { + id: createNightRatingInput.id as string, + rating, + date } await API.graphql( @@ -159,38 +152,11 @@ export const rateNight = ({ id, rating, date }: NightQuality) => async ( await dispatch(pushNightQuality(newNightRating)) } } - - // --- CAN DELETE --- - // else { - // // If record already exists, we update it - // if (checkRecordExists(nightQuality, date)) { - // await dispatch(updateNightQualityLocally(newNightRating)) - // } - // // If not, we handle it as local data - // else { - // // If the new night rating will break the size, we pop the 1st element (the oldest night rating) so the array always remains 31 elements - // if (checkIfWillExceedQuantity(nightQuality)) { - // await dispatch(popNightQualityLocally()) - // } - - // // Push the new one in as the 31st element - // await dispatch(pushNightQualityLocally(newNightRating)) - // } - // } } catch (err) { console.log('rateNight', err) } } const checkRecordExists = ({ records }: NightQualityState, date: string) => { - // const index = records.findIndex((nightQuality) => (nightQuality.id = date)) - - // return index !== -1 return records.has(date) } - -// --- CAN DELETE --- -// const checkIfWillExceedQuantity = ({ records }: NightQualityState) => { -// // return records.length === 31 -// return records.size === 31 -// } From a576aa072cc6621b0d906b26605297ec1ad87869 Mon Sep 17 00:00:00 2001 From: = <=> Date: Wed, 9 Sep 2020 12:54:42 +0300 Subject: [PATCH 12/13] Create react query for getting Ratings from Clouds + fix minor translation bugs --- src/queries/get-ratings-from-cloud.ts | 53 ++++++++++++++++++++++++++ src/screens/Auth/Login.tsx | 4 +- src/screens/main/main.tsx | 7 ++-- src/store/actions/StartupActions.ts | 4 -- src/store/actions/auth/auth-actions.ts | 2 - 5 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 src/queries/get-ratings-from-cloud.ts diff --git a/src/queries/get-ratings-from-cloud.ts b/src/queries/get-ratings-from-cloud.ts new file mode 100644 index 0000000..907c9a4 --- /dev/null +++ b/src/queries/get-ratings-from-cloud.ts @@ -0,0 +1,53 @@ +import { useQuery } from 'react-query' +import { useSelector, useDispatch } from 'react-redux' +import { getAuthState } from 'store/selectors/auth-selectors/auth-selectors' +import { ModelNightRatingFilterInput } from 'API' +import { getUsername } from 'store/selectors/UserSelectors' +import { API, graphqlOperation } from 'aws-amplify' +import { listNightRatings } from 'graphql/queries' +import { NightQuality } from 'Types/Sleep/NightQuality' +import { loadNightQualityFromCloud, convertNightQualityFromCloudToMap } from 'store/actions/sleep/night-quality-actions' + +interface GetRatingsFromCloud {} + +export const useGetRatingsFromCloud = (props: GetRatingsFromCloud) => { + const authenticated = useSelector(getAuthState) + const username = useSelector(getUsername) + const dispatch = useDispatch() + + if (authenticated) { + const { isLoading, isError, data, error } = useQuery( + ['getRatingsFromCloud'], + async () => { + try { + const variables: { + filter: ModelNightRatingFilterInput + limit?: number + nextToken?: string + } = { + filter: { + userId: { + eq: username + } + } + } + + const response = (await API.graphql( + graphqlOperation(listNightRatings, variables) + )) as any + + const cloudNightRatings: Array = + response.data.listNightRatings.items + + await dispatch( + loadNightQualityFromCloud( + convertNightQualityFromCloudToMap(cloudNightRatings) + ) + ) + } catch (err) { + console.log('getRatingsFromCloud react query', err) + } + } + ) + } +} diff --git a/src/screens/Auth/Login.tsx b/src/screens/Auth/Login.tsx index 496efa3..094b758 100644 --- a/src/screens/Auth/Login.tsx +++ b/src/screens/Auth/Login.tsx @@ -66,7 +66,7 @@ const SignInScreen = ({ navigation }: Props) => { autoCompleteType="email" returnKeyType="next" value={values.email} - error={touched.email ? errors.email : ''} + error={touched.email && errors.email} blurOnSubmit={false} enablesReturnKeyAutomatically autoCapitalize="none" @@ -82,7 +82,7 @@ const SignInScreen = ({ navigation }: Props) => { textContentType="password" autoCompleteType="password" value={values.password} - error={touched.password ? errors.password : ''} + error={touched.password && errors.password} returnKeyType="done" enablesReturnKeyAutomatically placeholder="INPUT_PASSWORD" diff --git a/src/screens/main/main.tsx b/src/screens/main/main.tsx index d595123..5589503 100644 --- a/src/screens/main/main.tsx +++ b/src/screens/main/main.tsx @@ -29,7 +29,7 @@ import { SafeAreaView } from '@components/Primitives/Primitives' import TopInfo from '@components/TopInfo' import colors from '../../styles/colors' import { getAuthState } from 'store/selectors/auth-selectors/auth-selectors' -import { getNightRatingsFromCloud } from 'store/actions/sleep/night-quality-actions' +import { useGetRatingsFromCloud } from 'queries/get-ratings-from-cloud' const MainScreen = () => { const isLoadingSleepData = useSelector(getHealthKitLoading) @@ -38,6 +38,8 @@ const MainScreen = () => { const dispatch = useDispatch() const authenticated = useSelector(getAuthState) + useGetRatingsFromCloud() + useNotificationEventHandlers() useEffect(() => { @@ -51,9 +53,6 @@ const MainScreen = () => { const checkSleepData = async () => { await dispatch(fetchSleepData()) await dispatch(updateCalendar()) - if (authenticated) { - await dispatch(getNightRatingsFromCloud()) - } } return ( diff --git a/src/store/actions/StartupActions.ts b/src/store/actions/StartupActions.ts index 09e8017..0f441a1 100644 --- a/src/store/actions/StartupActions.ts +++ b/src/store/actions/StartupActions.ts @@ -23,7 +23,6 @@ import { import { prepareSleepDataFetching } from './sleep/health-kit-actions' import { fetchSleepData, updateCalendar } from './sleep/sleep-data-actions' import { updateSubscriptionStatus } from './subscription/subscription-actions' -import { getNightRatingsFromCloud } from './sleep/night-quality-actions' export const startup = (): Thunk => async ( dispatch: Dispatch, @@ -60,9 +59,6 @@ export const startup = (): Thunk => async ( if (isAuthenticated) { await dispatch(updateCoachingInCloud()) - - // Get Night Ratings from Cloud - await dispatch(getNightRatingsFromCloud()) } await dispatch(calculateInsights()) diff --git a/src/store/actions/auth/auth-actions.ts b/src/store/actions/auth/auth-actions.ts index 0c98f41..44be5ee 100644 --- a/src/store/actions/auth/auth-actions.ts +++ b/src/store/actions/auth/auth-actions.ts @@ -14,7 +14,6 @@ import Purchases from 'react-native-purchases' import { GetState } from 'Types/GetState' import { NotificationType } from 'Types/NotificationState' import { updateEmail } from '../user/user-actions' -import { getNightRatingsFromCloud } from '../sleep/night-quality-actions' /* ACTION TYPES */ @@ -164,7 +163,6 @@ export const login = (loginEmail: string, loginPassword: string) => async ( await NavigationService.navigate(ROUTE.SLEEP, {}) } - await dispatch(getNightRatingsFromCloud(username)) await dispatch(loginSuccess(true, email, username)) } catch (error) { console.warn(error) From 4c89ad75ee0d16fbb3c8aa3348eee444cd291b80 Mon Sep 17 00:00:00 2001 From: = <=> Date: Wed, 9 Sep 2020 14:13:59 +0300 Subject: [PATCH 13/13] Update work on Night Ratings query, add it to the correct file --- .../get-ratings-from-cloud.ts | 31 +++++++++++++------ src/screens/main/main.tsx | 5 --- src/screens/sleep/SleepView.tsx | 6 +++- 3 files changed, 27 insertions(+), 15 deletions(-) rename src/queries/{ => night-ratings}/get-ratings-from-cloud.ts (61%) diff --git a/src/queries/get-ratings-from-cloud.ts b/src/queries/night-ratings/get-ratings-from-cloud.ts similarity index 61% rename from src/queries/get-ratings-from-cloud.ts rename to src/queries/night-ratings/get-ratings-from-cloud.ts index 907c9a4..5d529ce 100644 --- a/src/queries/get-ratings-from-cloud.ts +++ b/src/queries/night-ratings/get-ratings-from-cloud.ts @@ -1,24 +1,28 @@ import { useQuery } from 'react-query' import { useSelector, useDispatch } from 'react-redux' -import { getAuthState } from 'store/selectors/auth-selectors/auth-selectors' import { ModelNightRatingFilterInput } from 'API' -import { getUsername } from 'store/selectors/UserSelectors' import { API, graphqlOperation } from 'aws-amplify' import { listNightRatings } from 'graphql/queries' import { NightQuality } from 'Types/Sleep/NightQuality' -import { loadNightQualityFromCloud, convertNightQualityFromCloudToMap } from 'store/actions/sleep/night-quality-actions' +import { + loadNightQualityFromCloud, + convertNightQualityFromCloudToMap +} from 'store/actions/sleep/night-quality-actions' -interface GetRatingsFromCloud {} +import { actionCreators as newNotificationCreator } from 'store/Reducers/NotificationReducer' +import { NotificationType } from 'Types/NotificationState' +import { getAuthState } from 'store/Selectors/auth-selectors/auth-selectors' +import { getUsername } from 'store/Selectors/UserSelectors' -export const useGetRatingsFromCloud = (props: GetRatingsFromCloud) => { +export const useGetRatingsFromCloud = () => { const authenticated = useSelector(getAuthState) const username = useSelector(getUsername) const dispatch = useDispatch() - if (authenticated) { - const { isLoading, isError, data, error } = useQuery( - ['getRatingsFromCloud'], - async () => { + const { isError, error } = useQuery( + ['getRatingsFromCloud', { username }], + async () => { + if (authenticated) { try { const variables: { filter: ModelNightRatingFilterInput @@ -48,6 +52,15 @@ export const useGetRatingsFromCloud = (props: GetRatingsFromCloud) => { console.log('getRatingsFromCloud react query', err) } } + } + ) + + if (isError) { + dispatch( + newNotificationCreator.newNotification({ + message: (error).message as string, + type: NotificationType.ERROR + }) ) } } diff --git a/src/screens/main/main.tsx b/src/screens/main/main.tsx index 5589503..4e323c0 100644 --- a/src/screens/main/main.tsx +++ b/src/screens/main/main.tsx @@ -28,17 +28,12 @@ import NewHabitModal from '@components/modals/HabitModal/NewHabitModal' import { SafeAreaView } from '@components/Primitives/Primitives' import TopInfo from '@components/TopInfo' import colors from '../../styles/colors' -import { getAuthState } from 'store/selectors/auth-selectors/auth-selectors' -import { useGetRatingsFromCloud } from 'queries/get-ratings-from-cloud' const MainScreen = () => { const isLoadingSleepData = useSelector(getHealthKitLoading) const isLoadingFitbit = useSelector(getLoadingFitbit) const isLoadingGoogleFit = useSelector(getLoadingGoogleFit) const dispatch = useDispatch() - const authenticated = useSelector(getAuthState) - - useGetRatingsFromCloud() useNotificationEventHandlers() diff --git a/src/screens/sleep/SleepView.tsx b/src/screens/sleep/SleepView.tsx index 9d216a5..42b0b6a 100644 --- a/src/screens/sleep/SleepView.tsx +++ b/src/screens/sleep/SleepView.tsx @@ -26,14 +26,18 @@ import React, { FC, useEffect } from 'react' import { ScrollView } from 'react-native-gesture-handler' import { useDispatch, useSelector } from 'react-redux' import styled from 'styled-components/native' +import { + useGetRatingsFromCloud, +} from 'queries/night-ratings/get-ratings-from-cloud' const Sleep: FC = () => { const today = useSelector(getSelectedDay) const editModeOn = useSelector(getEditMode) const isLoadingSleepData = useSelector(getHealthKitLoading) - const dispatch = useDispatch() + useGetRatingsFromCloud() + useNotificationEventHandlers() useEffect(() => {