diff --git a/packages/alexa/src/graphql/get-report.ts b/packages/alexa/src/graphql/get-report.ts index 03d73627..76ef3d5a 100644 --- a/packages/alexa/src/graphql/get-report.ts +++ b/packages/alexa/src/graphql/get-report.ts @@ -32,6 +32,7 @@ const query = gql` entries { id time + time_split } } } diff --git a/packages/alexa/src/helpers/report.ts b/packages/alexa/src/helpers/report.ts index 8410c593..d8751cd8 100644 --- a/packages/alexa/src/helpers/report.ts +++ b/packages/alexa/src/helpers/report.ts @@ -4,7 +4,7 @@ import { getLaraConfig } from '../graphql/config' type ReducedDay = Pick & { entries: Pick[] } const totalDayMinutes = (day: ReducedDay) => - day.entries.reduce((acc, entry) => acc + (entry.time ? entry.time : entry.time_split!), 0) + day.entries.reduce((acc, entry) => acc + (entry.time ?? entry.time_split ?? 0), 0) export const finishedDays = async (days: ReducedDay[]): Promise => { const config = await getLaraConfig() diff --git a/packages/frontend/src/components/entry-input.tsx b/packages/frontend/src/components/entry-input.tsx index 847f43dd..26b2855a 100644 --- a/packages/frontend/src/components/entry-input.tsx +++ b/packages/frontend/src/components/entry-input.tsx @@ -187,14 +187,19 @@ const EntryInput: React.FC = ({ const handleSave = (newEntry: EntryInputType) => { setEditing(false) - if ( - !isValidTimeUpdate(day, newEntry.time ? newEntry.time - entry.time! : newEntry.time_split! - entry.time_split!) - ) { + const previousTime = !secondary ? (entry.time ?? 0) : (entry.time_split ?? 0) + const nextTime = !secondary ? (newEntry.time ?? 0) : (newEntry.time_split ?? 0) + + if (!isValidTimeUpdate(day, nextTime - previousTime)) { addToast({ text: strings.entryStatus.changeError, type: 'error' }) return } - if (newEntry.text === entry.text && newEntry.time === entry.time) { + const isUnchanged = !secondary + ? newEntry.text === entry.text && newEntry.time === entry.time + : newEntry.text_split === entry.text_split && newEntry.time_split === entry.time_split + + if (isUnchanged) { return } diff --git a/packages/frontend/src/components/suggestions.tsx b/packages/frontend/src/components/suggestions.tsx index 46ecfffa..8ad8ca8d 100644 --- a/packages/frontend/src/components/suggestions.tsx +++ b/packages/frontend/src/components/suggestions.tsx @@ -73,7 +73,14 @@ const Suggestions: React.FC = ({ submitTextSuggestion, submitTi case 'Enter': // submit the suggestion if shift isn't pressed if (!event.shiftKey && focusIndex > -1) { - setWaitingForBlur(suggestions[focusIndex]) + event.preventDefault() + const suggestionsTextWithTime = suggestionsWithTimes[focusIndex] + if (suggestionsTextWithTime) { + setWaitingForBlur(suggestionsTextWithTime.text) + setWaitingForBlurTimeSuggestion(suggestionsTextWithTime.time) + } else { + setWaitingForBlur(suggestions[focusIndex]) + } } break case 'ArrowUp': @@ -104,7 +111,7 @@ const Suggestions: React.FC = ({ submitTextSuggestion, submitTi break } }, - [setWaitingForBlur, focusIndex, inputRef, suggestions] + [setWaitingForBlur, focusIndex, inputRef, suggestions, suggestionsWithTimes] ) React.useEffect(() => { diff --git a/packages/frontend/src/graphql/index.tsx b/packages/frontend/src/graphql/index.tsx index b226b619..2c662a7c 100644 --- a/packages/frontend/src/graphql/index.tsx +++ b/packages/frontend/src/graphql/index.tsx @@ -718,7 +718,7 @@ export type CreateEntryMutationVariables = Exact<{ }>; -export type CreateEntryMutation = { __typename?: 'Mutation', createEntry: { __typename?: 'MutateEntryPayload', day: { __typename: 'Day', id: string, entries: Array<{ __typename?: 'Entry', id: string, text?: string | undefined, time?: number | undefined, orderId: number, comments: Array<{ __typename?: 'Comment', id: string }> }> } } }; +export type CreateEntryMutation = { __typename?: 'Mutation', createEntry: { __typename?: 'MutateEntryPayload', day: { __typename: 'Day', id: string, entries: Array<{ __typename?: 'Entry', id: string, text?: string | undefined, time?: number | undefined, text_split?: string | undefined, time_split?: number | undefined, orderId: number, comments: Array<{ __typename?: 'Comment', id: string }> }> } } }; export type CreateOAuthCodeMutationVariables = Exact<{ [key: string]: never; }>; @@ -973,7 +973,7 @@ export type AlexaLinkingUrlQuery = { __typename?: 'Query', alexaLinkingUrl?: str export type ArchivePageDataQueryVariables = Exact<{ [key: string]: never; }>; -export type ArchivePageDataQuery = { __typename?: 'Query', currentUser?: { __typename?: 'Admin', id: string, theme?: string | undefined, firstName: string, lastName: string, language?: string | undefined } | { __typename?: 'Trainee', id: string, theme?: string | undefined, firstName: string, lastName: string, language?: string | undefined } | { __typename?: 'Trainer', id: string, theme?: string | undefined, firstName: string, lastName: string, language?: string | undefined } | undefined, reports: Array<{ __typename: 'Report', id: string, week: number, year: number, status: ReportStatus, department?: string | undefined, summary?: string | undefined, traineeId: string, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, entries: Array<{ __typename?: 'Entry', id: string, time?: number | undefined, time_split?: number | undefined, text?: string | undefined, text_split?: string | undefined }> }> } | undefined> }; +export type ArchivePageDataQuery = { __typename?: 'Query', currentUser?: { __typename?: 'Admin', id: string, theme?: string | undefined, firstName: string, lastName: string, language?: string | undefined } | { __typename?: 'Trainee', id: string, theme?: string | undefined, firstName: string, lastName: string, language?: string | undefined } | { __typename?: 'Trainer', id: string, theme?: string | undefined, firstName: string, lastName: string, language?: string | undefined } | undefined, reports: Array<{ __typename: 'Report', id: string, week: number, year: number, status: ReportStatus, department?: string | undefined, summary?: string | undefined, traineeId: string, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, entries: Array<{ __typename?: 'Entry', id: string, time?: number | undefined, time_split?: number | undefined, text?: string | undefined }> }> } | undefined> }; export type AvatarSettingsDataQueryVariables = Exact<{ [key: string]: never; }>; @@ -1001,7 +1001,7 @@ export type DashboardPageDataQueryVariables = Exact<{ }>; -export type DashboardPageDataQuery = { __typename?: 'Query', currentUser?: { __typename?: 'Admin', id: string, theme?: string | undefined } | { __typename?: 'Trainee', id: string, theme?: string | undefined } | { __typename?: 'Trainer', id: string, theme?: string | undefined } | undefined, reports: Array<{ __typename: 'Report', id: string, week: number, year: number, status: ReportStatus, department?: string | undefined, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, entries: Array<{ __typename?: 'Entry', id: string, time?: number | undefined }> }> } | undefined>, reportForYearAndWeek?: { __typename?: 'Report', id: string, status: ReportStatus, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, date: string, id: string, entries: Array<{ __typename?: 'Entry', id: string, text?: string | undefined, time?: number | undefined, orderId: number, comments: Array<{ __typename?: 'Comment', id: string, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }>, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }> } | undefined }; +export type DashboardPageDataQuery = { __typename?: 'Query', currentUser?: { __typename?: 'Admin', id: string, theme?: string | undefined } | { __typename?: 'Trainee', id: string, theme?: string | undefined } | { __typename?: 'Trainer', id: string, theme?: string | undefined } | undefined, reports: Array<{ __typename: 'Report', id: string, week: number, year: number, status: ReportStatus, department?: string | undefined, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, entries: Array<{ __typename?: 'Entry', id: string, time?: number | undefined, time_split?: number | undefined }> }> } | undefined>, reportForYearAndWeek?: { __typename?: 'Report', id: string, status: ReportStatus, days: Array<{ __typename?: 'Day', status?: DayStatusEnum | undefined, date: string, id: string, entries: Array<{ __typename?: 'Entry', id: string, text?: string | undefined, time?: number | undefined, time_split?: number | undefined, orderId: number, comments: Array<{ __typename?: 'Comment', id: string, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }>, comments: Array<{ __typename?: 'Comment', id: string, text?: string | undefined, published: boolean, user: { __typename?: 'Admin', id: string, firstName: string, lastName: string } | { __typename?: 'Trainee', id: string, firstName: string, lastName: string } | { __typename?: 'Trainer', id: string, firstName: string, lastName: string } }> }> } | undefined }; export type DayInputDataQueryVariables = Exact<{ [key: string]: never; }>; @@ -1245,6 +1245,9 @@ export const CreateEntryDocument = gql` id text time + text_split + time_split + text_split orderId comments { id @@ -1971,7 +1974,7 @@ export const ArchivePageDataDocument = gql` time time_split text - text_split + time_split } } __typename @@ -2122,6 +2125,7 @@ export const DashboardPageDataDocument = gql` entries { id time + time_split } } __typename @@ -2137,6 +2141,7 @@ export const DashboardPageDataDocument = gql` id text time + time_split orderId comments { id diff --git a/packages/frontend/src/graphql/mutations/create-entry.gql b/packages/frontend/src/graphql/mutations/create-entry.gql index 9370fee1..cbfc016f 100644 --- a/packages/frontend/src/graphql/mutations/create-entry.gql +++ b/packages/frontend/src/graphql/mutations/create-entry.gql @@ -7,6 +7,9 @@ mutation createEntry($dayId: String!, $input: EntryInput!) { id text time + text_split + time_split + text_split orderId comments { id diff --git a/packages/frontend/src/graphql/queries/archive-page-data.gql b/packages/frontend/src/graphql/queries/archive-page-data.gql index 0b76c24d..27580ce2 100644 --- a/packages/frontend/src/graphql/queries/archive-page-data.gql +++ b/packages/frontend/src/graphql/queries/archive-page-data.gql @@ -21,7 +21,7 @@ query ArchivePageData { time time_split text - text_split + time_split } } __typename diff --git a/packages/frontend/src/graphql/queries/dashboard-page-data.gql b/packages/frontend/src/graphql/queries/dashboard-page-data.gql index 9098e895..e7757ff5 100644 --- a/packages/frontend/src/graphql/queries/dashboard-page-data.gql +++ b/packages/frontend/src/graphql/queries/dashboard-page-data.gql @@ -14,6 +14,7 @@ query DashboardPageData($currentYear: Int!, $currentWeek: Int!) { entries { id time + time_split } } __typename @@ -29,6 +30,7 @@ query DashboardPageData($currentYear: Int!, $currentWeek: Int!) { id text time + time_split orderId comments { id diff --git a/packages/frontend/src/helper/report-helper.ts b/packages/frontend/src/helper/report-helper.ts index 720623b2..98fae6c8 100644 --- a/packages/frontend/src/helper/report-helper.ts +++ b/packages/frontend/src/helper/report-helper.ts @@ -1,13 +1,16 @@ import { DefaultTheme } from '@lara/components' import { Day, DayStatusEnum, Entry, ReportStatus, useConfigQuery } from '../graphql' -import { useDayHelper } from './day-helper' + +type ReportDay = Pick & { + entries: Pick[] +} type UseReportHelper = { - getFinishedDays: (report: { days: (Pick & { entries: Pick[] })[] }) => number - getProgress: (report: { days: (Pick & { entries: Pick[] })[] }, value: number) => number + getFinishedDays: (report: { days: ReportDay[] }) => number + getProgress: (report: { days: ReportDay[] }, value: number) => number getStatusColor: (reportStatus: ReportStatus) => keyof DefaultTheme - getTotalMinutes: (report: { days: (Pick & { entries: Pick[] })[] }) => number + getTotalMinutes: (report: { days: ReportDay[] }) => number } const TraineeReportStatusColors: Record = { @@ -19,10 +22,12 @@ const TraineeReportStatusColors: Record = { export const useReportHelper = (): UseReportHelper => { const { data } = useConfigQuery() - const { getTotalMinutes: getTotalDayMinutes } = useDayHelper() const getStatusColor: UseReportHelper['getStatusColor'] = (reportStatus) => TraineeReportStatusColors[reportStatus] + const getDayMinutes = (day: ReportDay): number => + day.entries.reduce((acc, entry) => acc + (entry.time ?? entry.time_split ?? 0), 0) + const getFinishedDays: UseReportHelper['getFinishedDays'] = (report) => { let finishedDays = 0 @@ -30,6 +35,8 @@ export const useReportHelper = (): UseReportHelper => { const minWorkMinutes = data?.config.minWorkDayMinutes ?? 180 report.days.forEach((day) => { + const minutes = getDayMinutes(day) + switch (day.status) { case DayStatusEnum.Sick: case DayStatusEnum.Vacation: @@ -37,30 +44,30 @@ export const useReportHelper = (): UseReportHelper => { finishedDays++ break case DayStatusEnum.Education: - if (getTotalDayMinutes(day) > minEducationMinutes) { + if (minutes > minEducationMinutes) { finishedDays++ } break default: - if (getTotalDayMinutes(day) >= minWorkMinutes) { + if (minutes >= minWorkMinutes) { finishedDays++ } break } }) + return finishedDays } const getProgress: UseReportHelper['getProgress'] = (report, value) => { const done = value || getFinishedDays(report) - const finishedWeekDayCount = data?.config.finishedWeekDayCount ?? 5 return (done / finishedWeekDayCount) * 100 } const getTotalMinutes: UseReportHelper['getTotalMinutes'] = (report) => { - return report.days.reduce((accumulator, day) => accumulator + getTotalDayMinutes(day), 0) + return report.days.reduce((accumulator, day) => accumulator + getDayMinutes(day), 0) } return { diff --git a/packages/frontend/src/helper/time-conversion.ts b/packages/frontend/src/helper/time-conversion.ts index 7690fb07..605bb55c 100644 --- a/packages/frontend/src/helper/time-conversion.ts +++ b/packages/frontend/src/helper/time-conversion.ts @@ -19,7 +19,11 @@ class TimeConversion { return parseInt(input, 10) } } - public static minutesToString(minutes: number): string { + public static minutesToString(minutes: number | null | undefined): string { + if (minutes === null || minutes === undefined || Number.isNaN(minutes)) { + return '' + } + const rest = minutes % 60 const hours = (minutes - rest) / 60 return `${hours}:${rest < 10 ? `0${rest}` : rest}`